@de-otio/chaoskb-server 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/lib/constructs/blob-store.js +1 -1
  2. package/dist/lib/constructs/blob-store.js.map +1 -1
  3. package/dist/lib/handler/index.d.ts.map +1 -1
  4. package/dist/lib/handler/index.js +20 -4
  5. package/dist/lib/handler/index.js.map +1 -1
  6. package/dist/lib/handler/index.ts +19 -4
  7. package/dist/lib/handler/middleware/rate-limit.d.ts.map +1 -1
  8. package/dist/lib/handler/middleware/rate-limit.js +13 -9
  9. package/dist/lib/handler/middleware/rate-limit.js.map +1 -1
  10. package/dist/lib/handler/middleware/rate-limit.ts +14 -9
  11. package/dist/lib/handler/middleware/ssh-auth.d.ts.map +1 -1
  12. package/dist/lib/handler/middleware/ssh-auth.js +66 -6
  13. package/dist/lib/handler/middleware/ssh-auth.js.map +1 -1
  14. package/dist/lib/handler/middleware/ssh-auth.ts +74 -7
  15. package/dist/lib/handler/routes/audit.js +1 -1
  16. package/dist/lib/handler/routes/audit.js.map +1 -1
  17. package/dist/lib/handler/routes/audit.ts +1 -1
  18. package/dist/lib/handler/routes/blobs.d.ts.map +1 -1
  19. package/dist/lib/handler/routes/blobs.js +2 -3
  20. package/dist/lib/handler/routes/blobs.js.map +1 -1
  21. package/dist/lib/handler/routes/blobs.ts +2 -3
  22. package/dist/lib/handler/routes/devices.d.ts.map +1 -1
  23. package/dist/lib/handler/routes/devices.js +19 -12
  24. package/dist/lib/handler/routes/devices.js.map +1 -1
  25. package/dist/lib/handler/routes/devices.ts +20 -12
  26. package/dist/lib/handler/routes/github.d.ts +15 -2
  27. package/dist/lib/handler/routes/github.d.ts.map +1 -1
  28. package/dist/lib/handler/routes/github.js +96 -22
  29. package/dist/lib/handler/routes/github.js.map +1 -1
  30. package/dist/lib/handler/routes/github.ts +68 -35
  31. package/dist/lib/handler/routes/invites.d.ts.map +1 -1
  32. package/dist/lib/handler/routes/invites.js +11 -13
  33. package/dist/lib/handler/routes/invites.js.map +1 -1
  34. package/dist/lib/handler/routes/invites.ts +11 -13
  35. package/dist/lib/handler/routes/notifications.js +1 -1
  36. package/dist/lib/handler/routes/notifications.js.map +1 -1
  37. package/dist/lib/handler/routes/notifications.ts +1 -1
  38. package/dist/lib/handler/routes/projects.d.ts.map +1 -1
  39. package/dist/lib/handler/routes/projects.js.map +1 -1
  40. package/dist/lib/handler/routes/projects.ts +0 -1
  41. package/dist/lib/handler/routes/register.d.ts +1 -1
  42. package/dist/lib/handler/routes/register.d.ts.map +1 -1
  43. package/dist/lib/handler/routes/register.js +104 -58
  44. package/dist/lib/handler/routes/register.js.map +1 -1
  45. package/dist/lib/handler/routes/register.ts +113 -66
  46. package/dist/lib/handler/routes/restore.d.ts.map +1 -1
  47. package/dist/lib/handler/routes/restore.js +1 -2
  48. package/dist/lib/handler/routes/restore.js.map +1 -1
  49. package/dist/lib/handler/routes/restore.ts +1 -2
  50. package/dist/lib/handler/routes/rotation.d.ts.map +1 -1
  51. package/dist/lib/handler/routes/rotation.js +23 -2
  52. package/dist/lib/handler/routes/rotation.js.map +1 -1
  53. package/dist/lib/handler/routes/rotation.ts +30 -2
  54. package/package.json +1 -1
@@ -43,6 +43,7 @@ const audit_js_1 = require("./audit.js");
43
43
  const client_ssm_1 = require("@aws-sdk/client-ssm");
44
44
  const logger_js_1 = require("../logger.js");
45
45
  const github_js_1 = require("./github.js");
46
+ const notifications_js_1 = require("./notifications.js");
46
47
  const CHALLENGE_EXPIRY_SECONDS = 60;
47
48
  const JSON_HEADERS = { 'Content-Type': 'application/json' };
48
49
  let cachedSignupsEnabled = null;
@@ -121,24 +122,24 @@ async function handleChallenge(ddb, tableName) {
121
122
  const nonce = crypto.randomBytes(32).toString('base64');
122
123
  const now = Math.floor(Date.now() / 1000);
123
124
  const ttl = now + CHALLENGE_EXPIRY_SECONDS + 60; // DynamoDB TTL: generous buffer
124
- const expiresAt = new Date((now + CHALLENGE_EXPIRY_SECONDS) * 1000).toISOString();
125
+ const expiresAtISO = new Date((now + CHALLENGE_EXPIRY_SECONDS) * 1000).toISOString();
125
126
  await ddb.send(new lib_dynamodb_1.PutCommand({
126
127
  TableName: tableName,
127
128
  Item: {
128
129
  PK: `CHALLENGE#${nonce}`,
129
130
  SK: 'META',
130
- expiresAt,
131
- ttl,
131
+ expiresAtISO,
132
+ expiresAt: ttl,
132
133
  },
133
134
  }));
134
135
  logger_js_1.logger.info('Registration challenge created');
135
136
  return {
136
137
  statusCode: 200,
137
138
  headers: JSON_HEADERS,
138
- body: JSON.stringify({ challenge: nonce, expiresAt }),
139
+ body: JSON.stringify({ challenge: nonce, expiresAt: expiresAtISO }),
139
140
  };
140
141
  }
141
- async function handleRegister(body, ddb, tableName, signupsParamName) {
142
+ async function handleRegister(body, ddb, tableName, signupsParamName, headers = {}) {
142
143
  // Check if signups are enabled
143
144
  const signupsEnabled = await checkSignupsEnabled(signupsParamName);
144
145
  if (!signupsEnabled) {
@@ -188,39 +189,39 @@ async function handleRegister(body, ddb, tableName, signupsParamName) {
188
189
  body: JSON.stringify({ error: 'invalid_request', message: 'Invalid SSH public key format' }),
189
190
  };
190
191
  }
191
- // Look up and consume the challenge nonce (single-use)
192
- const challengeResult = await ddb.send(new lib_dynamodb_1.GetCommand({
193
- TableName: tableName,
194
- Key: {
195
- PK: `CHALLENGE#${request.challengeNonce}`,
196
- SK: 'META',
197
- },
198
- }));
199
- if (!challengeResult.Item) {
200
- return {
201
- statusCode: 400,
202
- headers: JSON_HEADERS,
203
- body: JSON.stringify({ error: 'invalid_challenge', message: 'Challenge not found or already used' }),
204
- };
205
- }
206
- // Check challenge expiry
207
- if (new Date(challengeResult.Item['expiresAt']) < new Date()) {
208
- // Clean up expired challenge
209
- await ddb.send(new lib_dynamodb_1.DeleteCommand({
192
+ // Atomically consume the challenge nonce (single-use).
193
+ // Uses conditional delete to prevent TOCTOU race: only one request can consume a given nonce.
194
+ let challengeItem;
195
+ try {
196
+ const deleteResult = await ddb.send(new lib_dynamodb_1.DeleteCommand({
210
197
  TableName: tableName,
211
- Key: { PK: `CHALLENGE#${request.challengeNonce}`, SK: 'META' },
198
+ Key: {
199
+ PK: `CHALLENGE#${request.challengeNonce}`,
200
+ SK: 'META',
201
+ },
202
+ ConditionExpression: 'attribute_exists(PK)',
203
+ ReturnValues: 'ALL_OLD',
212
204
  }));
205
+ challengeItem = deleteResult.Attributes;
206
+ }
207
+ catch (err) {
208
+ if (err.name === 'ConditionalCheckFailedException') {
209
+ return {
210
+ statusCode: 400,
211
+ headers: JSON_HEADERS,
212
+ body: JSON.stringify({ error: 'invalid_challenge', message: 'Challenge not found or already used' }),
213
+ };
214
+ }
215
+ throw err;
216
+ }
217
+ // Check challenge expiry on the consumed item
218
+ if (!challengeItem || new Date(challengeItem['expiresAtISO']) < new Date()) {
213
219
  return {
214
220
  statusCode: 400,
215
221
  headers: JSON_HEADERS,
216
222
  body: JSON.stringify({ error: 'challenge_expired', message: 'Challenge has expired' }),
217
223
  };
218
224
  }
219
- // Consume the challenge (delete it — single-use)
220
- await ddb.send(new lib_dynamodb_1.DeleteCommand({
221
- TableName: tableName,
222
- Key: { PK: `CHALLENGE#${request.challengeNonce}`, SK: 'META' },
223
- }));
224
225
  // Verify the SSH signature of the challenge nonce against the public key
225
226
  const validSignature = verifyRegistrationSignature(request.publicKey, request.challengeNonce, request.signedChallenge);
226
227
  if (!validSignature) {
@@ -233,45 +234,79 @@ async function handleRegister(body, ddb, tableName, signupsParamName) {
233
234
  }
234
235
  // GitHub verification (if --github was provided)
235
236
  if (request.github) {
237
+ let keyVerified = false;
236
238
  try {
237
- const keyOnGitHub = await (0, github_js_1.verifyKeyOnGitHub)(request.publicKey, request.github);
238
- if (!keyOnGitHub) {
239
+ keyVerified = await (0, github_js_1.verifyKeyOnGitHub)(request.publicKey, request.github);
240
+ }
241
+ catch {
242
+ // GitHub unreachable or user not found — uniform response
243
+ }
244
+ if (!keyVerified) {
245
+ return {
246
+ statusCode: 400,
247
+ headers: JSON_HEADERS,
248
+ body: JSON.stringify({
249
+ error: 'github_verification_failed',
250
+ message: 'Could not verify key against this GitHub account',
251
+ }),
252
+ };
253
+ }
254
+ // Check if an existing tenant is associated with this GitHub username (auto-link)
255
+ const existingTenantId = await (0, github_js_1.findTenantByGitHub)(request.github, ddb, tableName);
256
+ if (existingTenantId) {
257
+ // Fresh-fetch GitHub keys (bypass cache) to ensure both device keys still appear
258
+ let freshKeys;
259
+ try {
260
+ freshKeys = await (0, github_js_1.fetchGitHubKeysFresh)(request.github);
261
+ }
262
+ catch {
263
+ // GitHub unreachable at auto-link time — fall back to normal registration
264
+ freshKeys = [];
265
+ }
266
+ // Verify the new device's key appears on the GitHub account (fresh data)
267
+ if (freshKeys.length > 0 && !(0, github_js_1.keyAppearsInGitHubKeys)(request.publicKey, freshKeys)) {
239
268
  return {
240
269
  statusCode: 400,
241
270
  headers: JSON_HEADERS,
242
271
  body: JSON.stringify({
243
- error: 'github_key_not_found',
244
- message: `Public key not found on GitHub account "${request.github}"`,
272
+ error: 'github_verification_failed',
273
+ message: 'Could not verify key against this GitHub account',
245
274
  }),
246
275
  };
247
276
  }
248
- }
249
- catch (err) {
250
- if (err instanceof github_js_1.GitHubVerificationError) {
277
+ if (freshKeys.length > 0) {
278
+ // Resolve location from CloudFront headers for the notification
279
+ const location = (0, notifications_js_1.resolveIpLocation)(headers);
280
+ const deviceInfo = {
281
+ ...request.deviceInfo,
282
+ location,
283
+ };
284
+ // Create notification for existing devices
285
+ await (0, notifications_js_1.createNotification)(existingTenantId, 'device_linked', deviceInfo, ddb, tableName);
286
+ // Audit event
287
+ await (0, audit_js_1.logAuditEvent)(ddb, tableName, existingTenantId, {
288
+ eventType: 'device-linked',
289
+ fingerprint: '',
290
+ metadata: {
291
+ publicKey: request.publicKey,
292
+ github: request.github,
293
+ ...(deviceInfo.hostname && { hostname: deviceInfo.hostname }),
294
+ },
295
+ });
296
+ logger_js_1.logger.info('GitHub auto-link: existing tenant found', {
297
+ existingTenantId,
298
+ github: request.github,
299
+ });
251
300
  return {
252
- statusCode: 400,
301
+ statusCode: 200,
253
302
  headers: JSON_HEADERS,
254
- body: JSON.stringify({ error: err.code, message: err.message }),
303
+ body: JSON.stringify({
304
+ status: 'auto_linked',
305
+ github: request.github,
306
+ }),
255
307
  };
256
308
  }
257
- throw err;
258
- }
259
- // Check if an existing tenant is associated with this GitHub username (auto-link)
260
- const existingTenantId = await (0, github_js_1.findTenantByGitHub)(request.github, ddb, tableName);
261
- if (existingTenantId) {
262
- logger_js_1.logger.info('GitHub auto-link: existing tenant found', {
263
- existingTenantId,
264
- github: request.github,
265
- });
266
- return {
267
- statusCode: 200,
268
- headers: JSON_HEADERS,
269
- body: JSON.stringify({
270
- status: 'auto_linked',
271
- tenantId: existingTenantId,
272
- github: request.github,
273
- }),
274
- };
309
+ // If fresh keys unavailable, fall through to normal registration
275
310
  }
276
311
  }
277
312
  const tenantId = tenantIdFromPublicKey(request.publicKey);
@@ -292,8 +327,19 @@ async function handleRegister(body, ddb, tableName, signupsParamName) {
292
327
  logger_js_1.logger.info('Tenant registered', { tenantId, operation: 'register' });
293
328
  // Store GitHub association if provided
294
329
  if (request.github) {
330
+ const claimed = await (0, github_js_1.storeGitHubReverseLookup)(request.github, tenantId, ddb, tableName);
331
+ if (!claimed) {
332
+ // Another tenant already claimed this GitHub username — uniform error
333
+ return {
334
+ statusCode: 400,
335
+ headers: JSON_HEADERS,
336
+ body: JSON.stringify({
337
+ error: 'github_verification_failed',
338
+ message: 'Could not verify key against this GitHub account',
339
+ }),
340
+ };
341
+ }
295
342
  await (0, github_js_1.storeGitHubAssociation)(tenantId, request.github, ddb, tableName);
296
- await (0, github_js_1.storeGitHubReverseLookup)(request.github, tenantId, ddb, tableName);
297
343
  }
298
344
  await (0, audit_js_1.logAuditEvent)(ddb, tableName, tenantId, {
299
345
  eventType: 'registered',
@@ -1 +1 @@
1
- {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../../lib/handler/routes/register.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../../lib/handler/routes/register.ts"],"names":[],"mappings":"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"}
@@ -1,21 +1,24 @@
1
1
  import * as crypto from 'crypto';
2
- import { DynamoDBDocumentClient, PutCommand, GetCommand, DeleteCommand } from '@aws-sdk/lib-dynamodb';
2
+ import { DynamoDBDocumentClient, PutCommand, DeleteCommand } from '@aws-sdk/lib-dynamodb';
3
3
  import { logAuditEvent } from './audit.js';
4
4
  import { GetParameterCommand, SSMClient } from '@aws-sdk/client-ssm';
5
5
  import { logger } from '../logger.js';
6
6
  import {
7
7
  verifyKeyOnGitHub,
8
+ fetchGitHubKeysFresh,
9
+ keyAppearsInGitHubKeys,
8
10
  storeGitHubAssociation,
9
11
  storeGitHubReverseLookup,
10
12
  findTenantByGitHub,
11
- GitHubVerificationError,
12
13
  } from './github.js';
14
+ import { createNotification, resolveIpLocation, type DeviceInfo } from './notifications.js';
13
15
 
14
16
  interface RegisterRequest {
15
17
  publicKey: string;
16
18
  signedChallenge: string;
17
19
  challengeNonce: string;
18
20
  github?: string;
21
+ deviceInfo?: DeviceInfo;
19
22
  }
20
23
 
21
24
  interface HandlerResponse {
@@ -119,7 +122,7 @@ export async function handleChallenge(
119
122
  const nonce = crypto.randomBytes(32).toString('base64');
120
123
  const now = Math.floor(Date.now() / 1000);
121
124
  const ttl = now + CHALLENGE_EXPIRY_SECONDS + 60; // DynamoDB TTL: generous buffer
122
- const expiresAt = new Date((now + CHALLENGE_EXPIRY_SECONDS) * 1000).toISOString();
125
+ const expiresAtISO = new Date((now + CHALLENGE_EXPIRY_SECONDS) * 1000).toISOString();
123
126
 
124
127
  await ddb.send(
125
128
  new PutCommand({
@@ -127,8 +130,8 @@ export async function handleChallenge(
127
130
  Item: {
128
131
  PK: `CHALLENGE#${nonce}`,
129
132
  SK: 'META',
130
- expiresAt,
131
- ttl,
133
+ expiresAtISO,
134
+ expiresAt: ttl,
132
135
  },
133
136
  }),
134
137
  );
@@ -138,7 +141,7 @@ export async function handleChallenge(
138
141
  return {
139
142
  statusCode: 200,
140
143
  headers: JSON_HEADERS,
141
- body: JSON.stringify({ challenge: nonce, expiresAt }),
144
+ body: JSON.stringify({ challenge: nonce, expiresAt: expiresAtISO }),
142
145
  };
143
146
  }
144
147
 
@@ -147,6 +150,7 @@ export async function handleRegister(
147
150
  ddb: DynamoDBDocumentClient,
148
151
  tableName: string,
149
152
  signupsParamName: string,
153
+ headers: Record<string, string> = {},
150
154
  ): Promise<HandlerResponse> {
151
155
  // Check if signups are enabled
152
156
  const signupsEnabled = await checkSignupsEnabled(signupsParamName);
@@ -202,34 +206,35 @@ export async function handleRegister(
202
206
  };
203
207
  }
204
208
 
205
- // Look up and consume the challenge nonce (single-use)
206
- const challengeResult = await ddb.send(
207
- new GetCommand({
208
- TableName: tableName,
209
- Key: {
210
- PK: `CHALLENGE#${request.challengeNonce}`,
211
- SK: 'META',
212
- },
213
- }),
214
- );
215
-
216
- if (!challengeResult.Item) {
217
- return {
218
- statusCode: 400,
219
- headers: JSON_HEADERS,
220
- body: JSON.stringify({ error: 'invalid_challenge', message: 'Challenge not found or already used' }),
221
- };
222
- }
223
-
224
- // Check challenge expiry
225
- if (new Date(challengeResult.Item['expiresAt'] as string) < new Date()) {
226
- // Clean up expired challenge
227
- await ddb.send(
209
+ // Atomically consume the challenge nonce (single-use).
210
+ // Uses conditional delete to prevent TOCTOU race: only one request can consume a given nonce.
211
+ let challengeItem: Record<string, unknown> | undefined;
212
+ try {
213
+ const deleteResult = await ddb.send(
228
214
  new DeleteCommand({
229
215
  TableName: tableName,
230
- Key: { PK: `CHALLENGE#${request.challengeNonce}`, SK: 'META' },
216
+ Key: {
217
+ PK: `CHALLENGE#${request.challengeNonce}`,
218
+ SK: 'META',
219
+ },
220
+ ConditionExpression: 'attribute_exists(PK)',
221
+ ReturnValues: 'ALL_OLD',
231
222
  }),
232
223
  );
224
+ challengeItem = deleteResult.Attributes;
225
+ } catch (err: unknown) {
226
+ if ((err as { name?: string }).name === 'ConditionalCheckFailedException') {
227
+ return {
228
+ statusCode: 400,
229
+ headers: JSON_HEADERS,
230
+ body: JSON.stringify({ error: 'invalid_challenge', message: 'Challenge not found or already used' }),
231
+ };
232
+ }
233
+ throw err;
234
+ }
235
+
236
+ // Check challenge expiry on the consumed item
237
+ if (!challengeItem || new Date(challengeItem['expiresAtISO'] as string) < new Date()) {
233
238
  return {
234
239
  statusCode: 400,
235
240
  headers: JSON_HEADERS,
@@ -237,14 +242,6 @@ export async function handleRegister(
237
242
  };
238
243
  }
239
244
 
240
- // Consume the challenge (delete it — single-use)
241
- await ddb.send(
242
- new DeleteCommand({
243
- TableName: tableName,
244
- Key: { PK: `CHALLENGE#${request.challengeNonce}`, SK: 'META' },
245
- }),
246
- );
247
-
248
245
  // Verify the SSH signature of the challenge nonce against the public key
249
246
  const validSignature = verifyRegistrationSignature(
250
247
  request.publicKey,
@@ -263,45 +260,84 @@ export async function handleRegister(
263
260
 
264
261
  // GitHub verification (if --github was provided)
265
262
  if (request.github) {
263
+ let keyVerified = false;
266
264
  try {
267
- const keyOnGitHub = await verifyKeyOnGitHub(request.publicKey, request.github);
268
- if (!keyOnGitHub) {
265
+ keyVerified = await verifyKeyOnGitHub(request.publicKey, request.github);
266
+ } catch {
267
+ // GitHub unreachable or user not found — uniform response
268
+ }
269
+
270
+ if (!keyVerified) {
271
+ return {
272
+ statusCode: 400,
273
+ headers: JSON_HEADERS,
274
+ body: JSON.stringify({
275
+ error: 'github_verification_failed',
276
+ message: 'Could not verify key against this GitHub account',
277
+ }),
278
+ };
279
+ }
280
+
281
+ // Check if an existing tenant is associated with this GitHub username (auto-link)
282
+ const existingTenantId = await findTenantByGitHub(request.github, ddb, tableName);
283
+ if (existingTenantId) {
284
+ // Fresh-fetch GitHub keys (bypass cache) to ensure both device keys still appear
285
+ let freshKeys: string[];
286
+ try {
287
+ freshKeys = await fetchGitHubKeysFresh(request.github);
288
+ } catch {
289
+ // GitHub unreachable at auto-link time — fall back to normal registration
290
+ freshKeys = [];
291
+ }
292
+
293
+ // Verify the new device's key appears on the GitHub account (fresh data)
294
+ if (freshKeys.length > 0 && !keyAppearsInGitHubKeys(request.publicKey, freshKeys)) {
269
295
  return {
270
296
  statusCode: 400,
271
297
  headers: JSON_HEADERS,
272
298
  body: JSON.stringify({
273
- error: 'github_key_not_found',
274
- message: `Public key not found on GitHub account "${request.github}"`,
299
+ error: 'github_verification_failed',
300
+ message: 'Could not verify key against this GitHub account',
275
301
  }),
276
302
  };
277
303
  }
278
- } catch (err) {
279
- if (err instanceof GitHubVerificationError) {
304
+
305
+ if (freshKeys.length > 0) {
306
+ // Resolve location from CloudFront headers for the notification
307
+ const location = resolveIpLocation(headers);
308
+ const deviceInfo: DeviceInfo = {
309
+ ...request.deviceInfo,
310
+ location,
311
+ };
312
+
313
+ // Create notification for existing devices
314
+ await createNotification(existingTenantId, 'device_linked', deviceInfo, ddb, tableName);
315
+
316
+ // Audit event
317
+ await logAuditEvent(ddb, tableName, existingTenantId, {
318
+ eventType: 'device-linked',
319
+ fingerprint: '',
320
+ metadata: {
321
+ publicKey: request.publicKey,
322
+ github: request.github,
323
+ ...(deviceInfo.hostname && { hostname: deviceInfo.hostname }),
324
+ },
325
+ });
326
+
327
+ logger.info('GitHub auto-link: existing tenant found', {
328
+ existingTenantId,
329
+ github: request.github,
330
+ });
280
331
  return {
281
- statusCode: 400,
332
+ statusCode: 200,
282
333
  headers: JSON_HEADERS,
283
- body: JSON.stringify({ error: err.code, message: err.message }),
334
+ body: JSON.stringify({
335
+ status: 'auto_linked',
336
+ github: request.github,
337
+ }),
284
338
  };
285
339
  }
286
- throw err;
287
- }
288
-
289
- // Check if an existing tenant is associated with this GitHub username (auto-link)
290
- const existingTenantId = await findTenantByGitHub(request.github, ddb, tableName);
291
- if (existingTenantId) {
292
- logger.info('GitHub auto-link: existing tenant found', {
293
- existingTenantId,
294
- github: request.github,
295
- });
296
- return {
297
- statusCode: 200,
298
- headers: JSON_HEADERS,
299
- body: JSON.stringify({
300
- status: 'auto_linked',
301
- tenantId: existingTenantId,
302
- github: request.github,
303
- }),
304
- };
340
+ // If fresh keys unavailable, fall through to normal registration
305
341
  }
306
342
  }
307
343
 
@@ -328,8 +364,19 @@ export async function handleRegister(
328
364
 
329
365
  // Store GitHub association if provided
330
366
  if (request.github) {
367
+ const claimed = await storeGitHubReverseLookup(request.github, tenantId, ddb, tableName);
368
+ if (!claimed) {
369
+ // Another tenant already claimed this GitHub username — uniform error
370
+ return {
371
+ statusCode: 400,
372
+ headers: JSON_HEADERS,
373
+ body: JSON.stringify({
374
+ error: 'github_verification_failed',
375
+ message: 'Could not verify key against this GitHub account',
376
+ }),
377
+ };
378
+ }
331
379
  await storeGitHubAssociation(tenantId, request.github, ddb, tableName);
332
- await storeGitHubReverseLookup(request.github, tenantId, ddb, tableName);
333
380
  }
334
381
 
335
382
  await logAuditEvent(ddb, tableName, tenantId, {
@@ -1 +1 @@
1
- {"version":3,"file":"restore.d.ts","sourceRoot":"","sources":["../../../../lib/handler/routes/restore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAA6B,MAAM,uBAAuB,CAAC;AAG1F,UAAU,eAAe;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,sBAAsB,EAC3B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CA0D1B"}
1
+ {"version":3,"file":"restore.d.ts","sourceRoot":"","sources":["../../../../lib/handler/routes/restore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAA6B,MAAM,uBAAuB,CAAC;AAG1F,UAAU,eAAe;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,sBAAsB,EAC3B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CAyD1B"}
@@ -31,8 +31,7 @@ async function handleRestore(blobId, tenantId, ddb, tableName) {
31
31
  await ddb.send(new lib_dynamodb_1.UpdateCommand({
32
32
  TableName: tableName,
33
33
  Key: { PK: `TENANT#${tenantId}`, SK: `BLOB#${blobId}` },
34
- UpdateExpression: 'REMOVE deletedAt, #ttl SET updatedAt = :updatedAt',
35
- ExpressionAttributeNames: { '#ttl': 'ttl' },
34
+ UpdateExpression: 'REMOVE deletedAt, expiresAt SET updatedAt = :updatedAt',
36
35
  ExpressionAttributeValues: { ':updatedAt': now },
37
36
  }));
38
37
  // Re-increment storage used
@@ -1 +1 @@
1
- {"version":3,"file":"restore.js","sourceRoot":"","sources":["../../../../lib/handler/routes/restore.ts"],"names":[],"mappings":";;AASA,sCA+DC;AAxED,wDAA0F;AAC1F,4CAAsC;AAQ/B,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,QAAgB,EAChB,GAA2B,EAC3B,SAAiB;IAEjB,kDAAkD;IAClD,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAC7B,IAAI,yBAAU,CAAC;QACb,SAAS,EAAE,SAAS;QACpB,GAAG,EAAE,EAAE,EAAE,EAAE,UAAU,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,MAAM,EAAE,EAAE;QACvD,oBAAoB,EAAE,eAAe;QACrC,wBAAwB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;KAC3C,CAAC,CACH,CAAC;IAEF,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnB,OAAO;YACL,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;SACxE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO;YACL,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;SAC/E,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAY,IAAI,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,2BAA2B;IAC3B,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,4BAAa,CAAC;QAChB,SAAS,EAAE,SAAS;QACpB,GAAG,EAAE,EAAE,EAAE,EAAE,UAAU,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,MAAM,EAAE,EAAE;QACvD,gBAAgB,EAAE,mDAAmD;QACrE,wBAAwB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;QAC3C,yBAAyB,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE;KACjD,CAAC,CACH,CAAC;IAEF,4BAA4B;IAC5B,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,4BAAa,CAAC;QAChB,SAAS,EAAE,SAAS;QACpB,GAAG,EAAE,EAAE,EAAE,EAAE,UAAU,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE;QAC7C,gBAAgB,EAAE,iDAAiD;QACnE,yBAAyB,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE;KACjD,CAAC,CACH,CAAC;IAEF,kBAAM,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;IAEjE,OAAO;QACL,UAAU,EAAE,GAAG;QACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;KACrD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"restore.js","sourceRoot":"","sources":["../../../../lib/handler/routes/restore.ts"],"names":[],"mappings":";;AASA,sCA8DC;AAvED,wDAA0F;AAC1F,4CAAsC;AAQ/B,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,QAAgB,EAChB,GAA2B,EAC3B,SAAiB;IAEjB,kDAAkD;IAClD,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,CAC7B,IAAI,yBAAU,CAAC;QACb,SAAS,EAAE,SAAS;QACpB,GAAG,EAAE,EAAE,EAAE,EAAE,UAAU,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,MAAM,EAAE,EAAE;QACvD,oBAAoB,EAAE,eAAe;QACrC,wBAAwB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;KAC3C,CAAC,CACH,CAAC;IAEF,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnB,OAAO;YACL,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;SACxE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO;YACL,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;SAC/E,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAY,IAAI,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,2BAA2B;IAC3B,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,4BAAa,CAAC;QAChB,SAAS,EAAE,SAAS;QACpB,GAAG,EAAE,EAAE,EAAE,EAAE,UAAU,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,MAAM,EAAE,EAAE;QACvD,gBAAgB,EAAE,wDAAwD;QAC1E,yBAAyB,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE;KACjD,CAAC,CACH,CAAC;IAEF,4BAA4B;IAC5B,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,4BAAa,CAAC;QAChB,SAAS,EAAE,SAAS;QACpB,GAAG,EAAE,EAAE,EAAE,EAAE,UAAU,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE;QAC7C,gBAAgB,EAAE,iDAAiD;QACnE,yBAAyB,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE;KACjD,CAAC,CACH,CAAC;IAEF,kBAAM,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;IAEjE,OAAO;QACL,UAAU,EAAE,GAAG;QACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;KACrD,CAAC;AACJ,CAAC"}
@@ -47,8 +47,7 @@ export async function handleRestore(
47
47
  new UpdateCommand({
48
48
  TableName: tableName,
49
49
  Key: { PK: `TENANT#${tenantId}`, SK: `BLOB#${blobId}` },
50
- UpdateExpression: 'REMOVE deletedAt, #ttl SET updatedAt = :updatedAt',
51
- ExpressionAttributeNames: { '#ttl': 'ttl' },
50
+ UpdateExpression: 'REMOVE deletedAt, expiresAt SET updatedAt = :updatedAt',
52
51
  ExpressionAttributeValues: { ':updatedAt': now },
53
52
  }),
54
53
  );
@@ -1 +1 @@
1
- {"version":3,"file":"rotation.d.ts","sourceRoot":"","sources":["../../../../lib/handler/routes/rotation.ts"],"names":[],"mappings":"AACA,OAAO,EACL,sBAAsB,EAMvB,MAAM,uBAAuB,CAAC;AAG/B,UAAU,eAAe;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AA6BD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,GAAG,EAAE,sBAAsB,EAC3B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CAoH1B;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,sBAAsB,EAC3B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CA6F1B"}
1
+ {"version":3,"file":"rotation.d.ts","sourceRoot":"","sources":["../../../../lib/handler/routes/rotation.ts"],"names":[],"mappings":"AACA,OAAO,EACL,sBAAsB,EAMvB,MAAM,uBAAuB,CAAC;AAG/B,UAAU,eAAe;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AA6BD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,GAAG,EAAE,sBAAsB,EAC3B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CAoI1B;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,sBAAsB,EAC3B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CA6F1B"}
@@ -44,8 +44,7 @@ function fingerprintFromPublicKey(publicKeyBase64) {
44
44
  return crypto.createHash('sha256').update(Buffer.from(publicKeyBase64, 'base64')).digest('base64');
45
45
  }
46
46
  function tenantIdFromPublicKey(publicKeyBase64) {
47
- const hash = crypto.createHash('sha256').update(publicKeyBase64).digest('hex');
48
- return hash.slice(0, 32);
47
+ return crypto.createHash('sha256').update(publicKeyBase64).digest('hex').slice(0, 32);
49
48
  }
50
49
  function isValidBase64(value) {
51
50
  if (!value || value.length < 4 || value.length > 8192)
@@ -153,6 +152,19 @@ async function handleRotateStart(tenantId, oldFingerprint, rawBody, ddb, tableNa
153
152
  updatedAt: now,
154
153
  },
155
154
  }));
155
+ // Write a KEY_ALIAS record so auth middleware can resolve the new key's
156
+ // derived tenantId back to this tenant during rotation
157
+ const newKeyTenantId = tenantIdFromPublicKey(request.newPublicKey);
158
+ await ddb.send(new lib_dynamodb_1.PutCommand({
159
+ TableName: tableName,
160
+ Item: {
161
+ PK: `KEY_ALIAS#${newKeyTenantId}`,
162
+ SK: 'META',
163
+ originalTenantId: tenantId,
164
+ newPublicKey: request.newPublicKey,
165
+ createdAt: now,
166
+ },
167
+ }));
156
168
  logger_js_1.logger.info('Key rotation started', { tenantId, oldFingerprint, newFingerprint });
157
169
  return {
158
170
  statusCode: 200,
@@ -287,5 +299,14 @@ async function completeRotation(tenantId, rotation, ddb, tableName) {
287
299
  SK: 'ROTATION',
288
300
  },
289
301
  }));
302
+ // Delete the KEY_ALIAS lookup record for the new key
303
+ const newKeyTenantId = tenantIdFromPublicKey(newPublicKey);
304
+ await ddb.send(new lib_dynamodb_1.DeleteCommand({
305
+ TableName: tableName,
306
+ Key: {
307
+ PK: `KEY_ALIAS#${newKeyTenantId}`,
308
+ SK: 'META',
309
+ },
310
+ }));
290
311
  }
291
312
  //# sourceMappingURL=rotation.js.map