Skip to content

Commit f047287

Browse files
committed
feat: watcher endpoints
1 parent 0605ea2 commit f047287

File tree

4 files changed

+122
-23
lines changed

4 files changed

+122
-23
lines changed

infrastructure/evault-core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@fastify/swagger": "^8.14.0",
2828
"@fastify/swagger-ui": "^3.0.0",
2929
"@testcontainers/neo4j": "^10.24.2",
30+
"axios": "^1.6.7",
3031
"fastify": "^4.26.2",
3132
"graphql": "^16.10.0",
3233
"graphql-type-json": "^0.3.2",

infrastructure/evault-core/src/http/server.ts

Lines changed: 116 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@ import swagger from "@fastify/swagger";
33
import swaggerUi from "@fastify/swagger-ui";
44
import { W3ID } from "../w3id/w3id";
55
import { LogEvent } from "w3id";
6-
import {
7-
WatcherSignatureRequest,
8-
WatcherRequest,
9-
TypedRequest,
10-
TypedReply,
11-
} from "./types";
6+
import axios from "axios";
7+
import { WatcherRequest, TypedRequest, TypedReply } from "./types";
8+
import { verifierCallback } from "../utils/signer";
9+
10+
interface WatcherSignatureRequest {
11+
w3id: string;
12+
logEntryId: string;
13+
proof: {
14+
signature: string;
15+
alg: string;
16+
kid: string;
17+
};
18+
}
1219

1320
export async function registerHttpRoutes(
1421
server: FastifyInstance
@@ -98,11 +105,19 @@ export async function registerHttpRoutes(
98105
description: "Post a signature for a specific log entry",
99106
body: {
100107
type: "object",
101-
required: ["w3id", "signature", "logEntryId"],
108+
required: ["w3id", "logEntryId", "proof"],
102109
properties: {
103110
w3id: { type: "string" },
104-
signature: { type: "string" },
105111
logEntryId: { type: "string" },
112+
proof: {
113+
type: "object",
114+
required: ["signature", "alg", "kid"],
115+
properties: {
116+
signature: { type: "string" },
117+
alg: { type: "string" },
118+
kid: { type: "string" },
119+
},
120+
},
106121
},
107122
},
108123
response: {
@@ -120,12 +135,51 @@ export async function registerHttpRoutes(
120135
request: TypedRequest<WatcherSignatureRequest>,
121136
reply: TypedReply
122137
) => {
123-
const { w3id, signature, logEntryId } = request.body;
124-
// TODO: Implement signature verification and storage
125-
return {
126-
success: true,
127-
message: "Signature stored successfully",
128-
};
138+
const { w3id, logEntryId, proof } = request.body;
139+
140+
try {
141+
const currentW3ID = await W3ID.get();
142+
if (!currentW3ID.logs) {
143+
throw new Error("W3ID must have logs enabled");
144+
}
145+
146+
const logEvent = await currentW3ID.logs.repository.findOne({
147+
versionId: logEntryId,
148+
});
149+
if (!logEvent) {
150+
throw new Error(`Log event not found with id ${logEntryId}`);
151+
}
152+
153+
const isValid = await verifierCallback(
154+
logEntryId,
155+
[proof],
156+
proof.kid.split("#")[0]
157+
);
158+
if (!isValid) {
159+
throw new Error("Invalid signature");
160+
}
161+
162+
const updatedLogEvent: LogEvent = {
163+
...logEvent,
164+
proofs: [...(logEvent.proofs || []), proof],
165+
};
166+
167+
await currentW3ID.logs.repository.create(updatedLogEvent);
168+
169+
return {
170+
success: true,
171+
message: "Signature stored successfully",
172+
};
173+
} catch (error) {
174+
console.error("Error storing signature:", error);
175+
return {
176+
success: false,
177+
message:
178+
error instanceof Error
179+
? error.message
180+
: "Failed to store signature",
181+
};
182+
}
129183
}
130184
);
131185

@@ -158,12 +212,54 @@ export async function registerHttpRoutes(
158212
},
159213
async (request: TypedRequest<WatcherRequest>, reply: TypedReply) => {
160214
const { w3id, logEntryId } = request.body;
161-
// TODO: Implement signature request logic
162-
return {
163-
success: true,
164-
message: "Signature request created",
165-
requestId: "req_" + Date.now(),
166-
};
215+
216+
try {
217+
// Resolve the W3ID to get its request endpoint
218+
const registryResponse = await axios.get(
219+
`http://localhost:4321/resolve?w3id=${w3id}`
220+
);
221+
const { requestWatcherSignature } = registryResponse.data;
222+
223+
// Get the current W3ID instance
224+
const currentW3ID = await W3ID.get();
225+
if (!currentW3ID.logs) {
226+
throw new Error("W3ID must have logs enabled");
227+
}
228+
229+
// Find the log event
230+
const logEvent = await currentW3ID.logs.repository.findOne({
231+
versionId: logEntryId,
232+
});
233+
if (!logEvent) {
234+
throw new Error(`Log event not found with id ${logEntryId}`);
235+
}
236+
237+
// Request signature from the watcher
238+
const response = await axios.post(requestWatcherSignature, {
239+
w3id: currentW3ID.id,
240+
logEntryId,
241+
signature: await currentW3ID.signJWT({
242+
sub: logEntryId,
243+
exp: Date.now() + 3600 * 1000, // 1 hour expiry
244+
}),
245+
});
246+
247+
return {
248+
success: true,
249+
message: "Signature request created",
250+
requestId: response.data.requestId,
251+
};
252+
} catch (error) {
253+
console.error("Error requesting signature:", error);
254+
return {
255+
success: false,
256+
message:
257+
error instanceof Error
258+
? error.message
259+
: "Failed to request signature",
260+
requestId: "",
261+
};
262+
}
167263
}
168264
);
169265
}

platforms/registry/src/consul.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@ export async function resolveService(w3id: string) {
1919
const address = `http://${services[0].ServiceAddress}:${services[0].ServicePort}`;
2020
return {
2121
graphql: `${address}/graphql`,
22-
voyager: `${address}/voyager`,
2322
whois: `${address}/whois`,
24-
logs: `${address}/logs`,
25-
requestWatcherSignature: `${address}/request-signature`,
23+
requestWatcherSignature: `${address}/watchers/request`,
24+
wathcerSignEndpoint: `${address}/watchers/request`,
2625
};
2726
}
2827
return null;

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)