+38
-7
@@ -117,10 +117,38 @@ func (c *apiClient) do(ctx context.Context, method, path string, body, out any)
|
||||
return nil
|
||||
}
|
||||
|
||||
func leadingZeroBitsClient(b []byte) int {
|
||||
n := 0
|
||||
for _, x := range b {
|
||||
if x == 0 {
|
||||
n += 8
|
||||
continue
|
||||
}
|
||||
for m := byte(0x80); m != 0 && x&m == 0; m >>= 1 {
|
||||
n++
|
||||
}
|
||||
break
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func solveProofClient(challenge, cid string, bits int) string {
|
||||
if bits <= 0 {
|
||||
return ""
|
||||
}
|
||||
for i := uint64(0); ; i++ {
|
||||
counter := strconv.FormatUint(i, 10)
|
||||
h := sha256.Sum256([]byte("nh-pow-v1|" + challenge + "|" + cid + "|" + counter))
|
||||
if leadingZeroBitsClient(h[:]) >= bits {
|
||||
return counter
|
||||
}
|
||||
}
|
||||
}
|
||||
func (c *apiClient) login(ctx context.Context) error {
|
||||
var ch struct {
|
||||
ClientID string `json:"client_id"`
|
||||
Challenge string `json:"challenge"`
|
||||
ClientID string `json:"client_id"`
|
||||
Challenge string `json:"challenge"`
|
||||
ProofOfWorkBits int `json:"proof_of_work_bits"`
|
||||
}
|
||||
if err := c.do(ctx, http.MethodPost, "/api/auth/challenge", map[string]any{"public_jwk": c.id.PublicJWK}, &ch); err != nil {
|
||||
return fmt.Errorf("challenge: %w", err)
|
||||
@@ -133,10 +161,12 @@ func (c *apiClient) login(ctx context.Context) error {
|
||||
Token string `json:"token"`
|
||||
ClientID string `json:"client_id"`
|
||||
}
|
||||
pow := solveProofClient(ch.Challenge, ch.ClientID, ch.ProofOfWorkBits)
|
||||
if err := c.do(ctx, http.MethodPost, "/api/auth/login", map[string]any{
|
||||
"public_jwk": c.id.PublicJWK,
|
||||
"challenge": ch.Challenge,
|
||||
"signature": sig,
|
||||
"public_jwk": c.id.PublicJWK,
|
||||
"challenge": ch.Challenge,
|
||||
"signature": sig,
|
||||
"proof_of_work_counter": pow,
|
||||
}, &lg); err != nil {
|
||||
return fmt.Errorf("login: %w", err)
|
||||
}
|
||||
@@ -276,10 +306,11 @@ func (c *apiClient) dialWS(ctx context.Context, maxNodes int) (*websocket.Conn,
|
||||
scheme = "wss"
|
||||
}
|
||||
q := url.Values{}
|
||||
q.Set("token", c.token)
|
||||
q.Set("max_nodes", strconv.Itoa(maxNodes))
|
||||
wu := scheme + "://" + u.Host + "/api/ws?" + q.Encode()
|
||||
conn, resp, err := websocket.DefaultDialer.DialContext(ctx, wu, nil)
|
||||
h := http.Header{}
|
||||
h.Set("Authorization", "Bearer "+c.token)
|
||||
conn, resp, err := websocket.DefaultDialer.DialContext(ctx, wu, h)
|
||||
if err != nil && resp != nil {
|
||||
b, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
|
||||
_ = resp.Body.Close()
|
||||
|
||||
Reference in New Issue
Block a user