Skip to content
This repository was archived by the owner on Mar 26, 2025. It is now read-only.

Commit cafb80c

Browse files
authored
Merge pull request #31 from aibtcdev/fix/auth-flow
Fix auth and signature flow
2 parents 6294b3d + 9e14ce9 commit cafb80c

File tree

1 file changed

+27
-42
lines changed

1 file changed

+27
-42
lines changed

src/durable-objects/auth-do.ts

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
11
import { DurableObject } from 'cloudflare:workers';
2-
import { sha256 } from '@noble/hashes/sha256';
3-
import { bytesToHex } from '@stacks/common';
42
import { verifyMessageSignatureRsv } from '@stacks/encryption';
5-
import {
6-
encodeStructuredData,
7-
getAddressFromPublicKey,
8-
publicKeyFromSignatureRsv,
9-
stringAsciiCV,
10-
tupleCV,
11-
uintCV,
12-
validateStacksAddress,
13-
} from '@stacks/transactions';
3+
import { getAddressFromPublicKey, validateStacksAddress } from '@stacks/transactions';
144
import { Env } from '../../worker-configuration';
155
import { AppConfig } from '../config';
166
import { createJsonResponse } from '../utils/requests-responses';
@@ -96,71 +86,66 @@ export class AuthDO extends DurableObject<Env> {
9686
if (endpoint === '/request-auth-token') {
9787
// get signature from body
9888
const body = await request.json();
99-
if (!body || typeof body !== 'object' || !('data' in body)) {
89+
if (!body || typeof body !== 'object' || !('signature' in body) || !('publicKey' in body)) {
10090
return createJsonResponse(
10191
{
102-
error: 'Missing or invalid "data" in request body',
92+
error: 'Missing or invalid "signature" or "publicKey" in request body',
10393
},
10494
400
10595
);
10696
}
107-
const signedMessage = String(body.data);
97+
const signedMessage = String(body.signature);
98+
const publicKey = String(body.publicKey);
10899
// try to verify signature
109100
try {
110-
// TODO: this needs a home, corresponds with front-end settings
111-
// might fail signature check if it does not match
112-
const expectedDomain = tupleCV({
113-
name: stringAsciiCV('sprint.aibtc.dev'),
114-
version: stringAsciiCV('0.0.1'),
115-
'chain-id': uintCV(1), // hardcoded mainnet, testnet is u2147483648
116-
});
117-
// same here this has to match front-end
118-
const expectedMessage = stringAsciiCV('Welcome to aibtcdev!');
119-
const encodedMessage = encodeStructuredData({ message: expectedMessage, domain: expectedDomain });
120-
const encodedMessageHashed = sha256(encodedMessage);
121-
// get public key from signature
122-
const publicKey = publicKeyFromSignatureRsv(bytesToHex(encodedMessageHashed), signedMessage);
123-
// verify signature
101+
const expectedMessageText = 'welcome to aibtcdev!';
124102
const isSignatureVerified = verifyMessageSignatureRsv({
125103
signature: signedMessage, // what they sent us
126-
message: encodedMessageHashed, // what we expect
127-
publicKey: publicKey, // public key from signature
104+
message: expectedMessageText, // what we expect
105+
publicKey, // public key from signature
128106
});
107+
const addressFromPubkey = getAddressFromPublicKey(publicKey, 'mainnet');
108+
const isAddressValid = validateStacksAddress(addressFromPubkey);
109+
// check if signature is valid with the public key
129110
if (!isSignatureVerified) {
130111
return createJsonResponse(
131112
{
132-
error: `Failed to verify signature ${signedMessage}`,
113+
error: `Signature verification failed for public key ${publicKey}`,
133114
},
134115
401
135116
);
136117
}
137-
// get address from public key
138-
const addressFromPublicKey = getAddressFromPublicKey(publicKey, 'mainnet');
139-
// verify valid stacks address returned
140-
if (!validateStacksAddress(addressFromPublicKey)) {
118+
// check if address is valid
119+
if (!isAddressValid) {
141120
return createJsonResponse(
142121
{
143-
error: `Failed to get address from public key ${publicKey}`,
122+
error: `Invalid address ${addressFromPubkey} from public key ${publicKey}`,
144123
},
145-
401
124+
400
146125
);
147126
}
148127
// add address to kv key list with unique session key
149128
// expires after 30 days and requires new signature from user
150129
// signing before expiration extends the expiration
151130
const sessionToken = crypto.randomUUID();
152-
// first key allows us to filter by address
153-
await this.env.AIBTCDEV_SERVICES_KV.put(`${this.KEY_PREFIX}:address:${addressFromPublicKey}`, sessionToken, {
131+
// allow lookup of pubkey from address
132+
const savePubkey = this.env.AIBTCDEV_SERVICES_KV.put(`${this.KEY_PREFIX}:pubkey:${addressFromPubkey}`, publicKey, {
133+
expirationTtl: this.CACHE_TTL,
134+
});
135+
// allow lookup of address from session token
136+
const saveSessionToken = this.env.AIBTCDEV_SERVICES_KV.put(`${this.KEY_PREFIX}:session:${sessionToken}`, addressFromPubkey, {
154137
expirationTtl: this.CACHE_TTL,
155138
});
156-
// second key allows us to filter by session key
157-
await this.env.AIBTCDEV_SERVICES_KV.put(`${this.KEY_PREFIX}:session:${sessionToken}`, addressFromPublicKey, {
139+
// allow lookup of session token from address
140+
const saveAddress = this.env.AIBTCDEV_SERVICES_KV.put(`${this.KEY_PREFIX}:address:${addressFromPubkey}`, sessionToken, {
158141
expirationTtl: this.CACHE_TTL,
159142
});
143+
// wait for all kv operations to complete
144+
await Promise.all([savePubkey, saveSessionToken, saveAddress]);
160145
// return 200 with session token
161146
return createJsonResponse({
162147
message: 'auth token successfully created',
163-
address: addressFromPublicKey,
148+
address: addressFromPubkey,
164149
sessionToken,
165150
});
166151
} catch (error) {

0 commit comments

Comments
 (0)