@@ -11,6 +11,7 @@ import { hash } from "../utils/hash";
11
11
import {
12
12
isGenesisOptions ,
13
13
isRotationOptions ,
14
+ type Signer ,
14
15
type CreateLogEventOptions ,
15
16
type GenesisLogOptions ,
16
17
type LogEvent ,
@@ -28,15 +29,25 @@ import type { StorageSpec } from "./storage/storage-spec";
28
29
29
30
export class IDLogManager {
30
31
repository : StorageSpec < LogEvent , LogEvent > ;
32
+ signer : Signer ;
31
33
32
- constructor ( repository : StorageSpec < LogEvent , LogEvent > ) {
34
+ constructor ( repository : StorageSpec < LogEvent , LogEvent > , signer : Signer ) {
33
35
this . repository = repository ;
36
+ this . signer = signer ;
34
37
}
35
38
39
+ /**
40
+ * Validate a chain of W3ID logs
41
+ *
42
+ * @param {LogEvent[] } log
43
+ * @param {VerifierCallback } verifyCallback
44
+ * @returns {Promise<true> }
45
+ */
46
+
36
47
static async validateLogChain (
37
48
log : LogEvent [ ] ,
38
49
verifyCallback : VerifierCallback ,
39
- ) {
50
+ ) : Promise < true > {
40
51
let currIndex = 0 ;
41
52
let currentNextKeyHashesSeen : string [ ] = [ ] ;
42
53
let lastUpdateKeysSeen : string [ ] = [ ] ;
@@ -71,11 +82,19 @@ export class IDLogManager {
71
82
return true ;
72
83
}
73
84
85
+ /**
86
+ * Validate cryptographic signature on a single LogEvent
87
+ *
88
+ * @param {LogEvent } e
89
+ * @param {string[] } currentUpdateKeys
90
+ * @param {VerifierCallback } verifyCallback
91
+ * @returns {Promise<void> }
92
+ */
74
93
private static async verifyLogEventProof (
75
94
e : LogEvent ,
76
95
currentUpdateKeys : string [ ] ,
77
96
verifyCallback : VerifierCallback ,
78
- ) {
97
+ ) : Promise < void > {
79
98
const proof = e . proof ;
80
99
const copy = JSON . parse ( JSON . stringify ( e ) ) ;
81
100
// biome-ignore lint/performance/noDelete: we need to delete proof completely
@@ -94,8 +113,15 @@ export class IDLogManager {
94
113
if ( ! verified ) throw new BadSignatureError ( ) ;
95
114
}
96
115
116
+ /**
117
+ * Append a new log entry for a W3ID
118
+ *
119
+ * @param {LogEvent[] } entries
120
+ * @param {RotationLogOptions } options
121
+ * @returns Promise<LogEvent>
122
+ */
97
123
private async appendEntry ( entries : LogEvent [ ] , options : RotationLogOptions ) {
98
- const { signer , nextKeyHashes, nextKeySigner } = options ;
124
+ const { nextKeyHashes, nextKeySigner } = options ;
99
125
const latestEntry = entries [ entries . length - 1 ] ;
100
126
const logHash = await hash ( latestEntry ) ;
101
127
const index = Number ( latestEntry . versionId . split ( "-" ) [ 0 ] ) + 1 ;
@@ -113,30 +139,44 @@ export class IDLogManager {
113
139
method : "w3id:v0.0.0" ,
114
140
} ;
115
141
116
- const proof = await signer . sign ( canonicalize ( logEvent ) as string ) ;
142
+ const proof = await this . signer . sign ( canonicalize ( logEvent ) as string ) ;
117
143
logEvent . proof = proof ;
118
144
119
145
await this . repository . create ( logEvent ) ;
146
+ this . signer = nextKeySigner ;
120
147
return logEvent ;
121
148
}
122
149
150
+ /**
151
+ * Create genesis entry for a W3ID log
152
+ *
153
+ * @param {GenesisLogOptions } options
154
+ * @returns Promise<LogEvent>
155
+ */
123
156
private async createGenesisEntry ( options : GenesisLogOptions ) {
124
- const { id, nextKeyHashes, signer } = options ;
157
+ const { id, nextKeyHashes } = options ;
158
+ const idTag = id . includes ( "@" ) ? id . split ( "@" ) [ 1 ] : id ;
125
159
const logEvent : LogEvent = {
126
160
id,
127
- versionId : `0-${ id . split ( "@" ) [ 1 ] } ` ,
161
+ versionId : `0-${ idTag } ` ,
128
162
versionTime : new Date ( Date . now ( ) ) ,
129
- updateKeys : [ signer . pubKey ] ,
163
+ updateKeys : [ this . signer . pubKey ] ,
130
164
nextKeyHashes : nextKeyHashes ,
131
165
method : "w3id:v0.0.0" ,
132
166
} ;
133
- const proof = await signer . sign ( canonicalize ( logEvent ) as string ) ;
167
+ const proof = await this . signer . sign ( canonicalize ( logEvent ) as string ) ;
134
168
logEvent . proof = proof ;
135
169
await this . repository . create ( logEvent ) ;
136
170
return logEvent ;
137
171
}
138
172
139
- async createLogEvent ( options : CreateLogEventOptions ) {
173
+ /**
174
+ * Create a log event and save it to the repository
175
+ *
176
+ * @param {CreateLogEventOptions } options
177
+ * @returns Promise<LogEvent>
178
+ */
179
+ async createLogEvent ( options : CreateLogEventOptions ) : Promise < LogEvent > {
140
180
const entries = await this . repository . findMany ( { } ) ;
141
181
if ( entries . length > 0 ) {
142
182
if ( ! isRotationOptions ( options ) ) throw new BadOptionsSpecifiedError ( ) ;
0 commit comments