-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathSignature.ts
More file actions
64 lines (45 loc) · 1.57 KB
/
Signature.ts
File metadata and controls
64 lines (45 loc) · 1.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import { observable } from 'mobx';
import { BaseModel, persist, restore, toggle } from 'mobx-restful';
import { isServer } from './configuration';
export const buffer2hex = (buffer: ArrayBufferLike) =>
Array.from(new Uint8Array(buffer), x => x.toString(16).padStart(2, '0')).join('');
export class SignatureModel extends BaseModel {
algorithm = { name: 'ECDSA', namedCurve: 'P-384', hash: { name: 'SHA-256' } };
@persist()
@observable
accessor privateKey: CryptoKey | undefined;
@persist()
@observable
accessor publicKey = '';
@persist()
@observable
accessor signatureMap = {} as Record<string, string>;
restored = !isServer() && restore(this, 'Signature');
@toggle('uploading')
async makeKeyPair() {
await this.restored;
if (this.publicKey) return this.publicKey;
const { publicKey, privateKey } = await crypto.subtle.generateKey(this.algorithm, true, [
'sign',
'verify',
]);
this.privateKey = privateKey;
const JWK = await crypto.subtle.exportKey('jwk', publicKey);
return (this.publicKey = btoa(JSON.stringify(JWK)));
}
@toggle('uploading')
async sign(value: string) {
await this.restored;
let signature = this.signatureMap[value];
if (signature) return signature;
if (!this.publicKey) await this.makeKeyPair();
const rawSignature = await crypto.subtle.sign(
this.algorithm,
this.privateKey!,
new TextEncoder().encode(value),
);
signature = buffer2hex(rawSignature);
this.signatureMap = { ...this.signatureMap, [value]: signature };
return signature;
}
}