-
Notifications
You must be signed in to change notification settings - Fork 294
feat: new kms api example module branch #6119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
5d8bc23
059a4f2
d2f3a7d
a9977b7
8de1981
0757c42
7f126c0
2318ad5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,3 +17,4 @@ modules/**/dist/ | |
modules/**/pack-scoped/ | ||
coverage | ||
/.direnv/ | ||
*.db |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# KMS API example (REST API) | ||
|
||
Based on TDD specification [On-Prem Wallets(https://docs.google.com/document/d/1ku2agwirV3tHCJF350VF_uaVx73D6vu7yUBaDp-cxL0/edit?tab=t.0#heading=h.165ukudv7ejt)] | ||
|
||
Made with ExpressJS, Typescript and sqlite3. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"name": "examplekmsapi", | ||
"version": "1.0.0", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"dev": "npx tsx --watch src/app.ts", | ||
"dev-test": "npx tsx --watch src/index-test.ts", | ||
"build": "tsc -p .", | ||
"run": "node dist/src/app.js", | ||
"build-and-run": "tsc -p .; node dist/src/app.js" | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"license": "ISC", | ||
"description": "", | ||
"dependencies": { | ||
"@aws-sdk/client-kms": "^3.810.0", | ||
"@azure/identity": "^4.10.0", | ||
"@azure/keyvault-keys": "^4.9.0", | ||
"body-parser": "^2.2.0", | ||
"express": "^5.1.0", | ||
"sqlite3": "^5.1.7", | ||
"swagger-jsdoc": "^6.2.8", | ||
"swagger-ui-express": "^5.0.1", | ||
"zod": "^3.24.4" | ||
}, | ||
"devDependencies": { | ||
"@tsconfig/node22": "^22.0.1", | ||
"@types/express": "^5.0.1", | ||
"@types/node": "^22.15.17", | ||
"@types/swagger-jsdoc": "^6.0.4", | ||
"@types/swagger-ui-express": "^4.1.8", | ||
"tsx": "^4.19.4", | ||
"typescript": "^5.8.3" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
-- TODO: delete this comments! questions for Pranav/Mohammad | ||
-- Some fields with VARCHAR(X) not sure how many characters | ||
-- do we need for a coin. | ||
|
||
-- I took the fields from the TDD doc on page 3 | ||
-- Not sure also about the prv and pub key length, should we limit them? | ||
CREATE TABLE PRIVATE_KEYS( | ||
id TEXT PRIMARY KEY, | ||
coin VARCHAR(30) NOT NULL, | ||
source VARCHAR(15) CHECK(source IN ('user', 'backup')) NOT NULL, | ||
type VARCHAR(15) CHECK(type IN ('independent', 'tss')) NOT NULL, | ||
prv TEXT NOT NULL, | ||
pub TEXT NOT NULL); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { NextFunction, Request, Response } from 'express'; | ||
import db from '../../db'; | ||
import { KmsInterface } from '../../providers/kms-interface/kmsInterface'; | ||
|
||
type GetParamsType = { | ||
pub: string; | ||
}; | ||
|
||
/** | ||
* @openapi | ||
* /key/{pub}: | ||
* get: | ||
* summary: Retrieve a private key stored | ||
* tags: | ||
* - key management service | ||
* parameters: | ||
* - in: path | ||
* name: pub | ||
* required: true | ||
* schema: | ||
* type: string | ||
* description: Public key related to the priv key to retrieve | ||
* - in: query | ||
* name: source | ||
* required: true | ||
* schema: | ||
* type: string | ||
* enum: | ||
* - user | ||
* - backup | ||
* description: The kind of key to retrieve | ||
* responses: | ||
* 200: | ||
* description: Private key retrieved | ||
* content: | ||
* application/json: | ||
* schema: | ||
* type: object | ||
* required: | ||
* - prv | ||
* - pub | ||
* - coin | ||
* - source | ||
* - type | ||
* properties: | ||
* prv: | ||
* type: string | ||
* pub: | ||
* type: string | ||
* source: | ||
* type: string | ||
* enum: | ||
* - user | ||
* - backup | ||
* type: | ||
* type: string | ||
* enum: | ||
* - user | ||
* - backup | ||
* example: | ||
* prv: "MIICXAIBAAKBgH3D4WKfdvhhj9TSGrI0FxAmdfiyfOphuM/kmLMIMKdahZLE5b8YoPL5oIE5NT+157iyQptb7q7qY9nA1jw86Br79FIsi6hLOuAne+1u4jVyJi4PLFAK5gM0c9klGjiunJ+OSH7fX+HQDwykZm20bdEa2fRU4dqT/sRm4Ta1iwAfAgMBAAEC" | ||
* pub: "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgH3D4WKfdvhhj9TSGrI0FxAmdfiyfOphuM/kmLMIMKdahZLE5b8YoPL5oIE5NT+157iyQptb7q7qY9nA1jw86Br79FIsi6hLOuAne+1u4jVyJi4PLFAU4dqT/sRm4Ta1iwAfAgMBAAE=" | ||
* source: "user" | ||
* type: "independent" | ||
* 404: | ||
* description: Private key not found | ||
* 500: | ||
* description: Internal server error | ||
*/ | ||
export async function GET(req: Request<GetParamsType>, res: Response, next: NextFunction, kms: KmsInterface): Promise<void> { | ||
const { pub } = req.params; | ||
|
||
// fetch from DB | ||
const source = req.query.source; | ||
const data = await db.fetchOne('SELECT (encryptedPrv, kmsKey, type) FROM PRIVATE_KEY WHERE pub = ? AND source = ?', [pub, source]); | ||
if (!data) { | ||
res.status(404); | ||
res.send({ message: `Not Found` }) | ||
return; | ||
} | ||
|
||
const { encryptedPrv, kmsKey, type } = data; | ||
|
||
// fetch prv from kms | ||
const prv = await kms.getKey(kmsKey, encryptedPrv, {}) | ||
.catch((err) => { | ||
res.status(500); | ||
res.send({ message: 'Internal server error' }); | ||
return; // TODO: test this | ||
}); | ||
|
||
// TODO: i know that we could chain res.status() with .json but what's the preferred way? | ||
res.status(200); | ||
res.json({ prv, pub, source, type }); | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,144 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { NextFunction, Request, Response } from 'express'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import db from '../../db'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { KmsErrorRes, KmsInterface, PostKeyKmsRes } from '../../providers/kms-interface/kmsInterface'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { ZodPostKeySchema } from '../schemas/postKeySchema'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @openapi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* /key: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* post: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* summary: Store a new private key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* tags: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - key management service | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* requestBody: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* required: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* content: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* application/json: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* schema: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: object | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* required: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - prv | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - pub | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - coin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - source | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* properties: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* prv: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* pub: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* coin: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* source: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* enum: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - user | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - backup | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* enum: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - independent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - mpc | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* responses: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* 200: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* description: Successfully stored key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* content: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* application/json: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* schema: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: object | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* required: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - prv | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - pub | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - coin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - source | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* properties: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* keyId: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* coin: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* source: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* enum: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - user | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - backup | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* enum: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - independent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* - mpc | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* pub: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* example: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* keyId: "MIICXAIBAAKBgH3D4WKfdvhhj9TSGrI0FxAmdfiyfOphuM/kmLMIMKdahZLE5b8YoPL5oIE5NT+157iyQptb7q7qY9nA1jw86Br79FIsi6hLOuAne+1u4jVyJi4PLFAK5gM0c9klGjiunJ+OSH7fX+HQDwykZm20bdEa2fRU4dqT/sRm4Ta1iwAfAgMBAAEC" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* coin: "sol" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* source: "user" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* type: "tss" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* pub: "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgH3D4WKfdvhhj9TSGrI0FxAmdfiyfOphuM/kmLMIMKdahZLE5b8YoPL5oIE5NT+157iyQptb7q7qY9nA1jw86Br79FIsi6hLOuAne+1u4jVyJi4PLFAU4dqT/sRm4Ta1iwAfAgMBAAE=" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* 400: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* description: Invalid data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* 409: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* description: Duplicate key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* 500: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* description: Internal server error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export async function POST(req: Request, res: Response, next: NextFunction, kms: KmsInterface): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// parse request | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ZodPostKeySchema.parse(req.body); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(400); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.send({ message: 'Invalid data provided from client' }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { prv, pub, coin, source, type } = req.body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// check for duplicates | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const keyObject = await db.fetchAll('SELECT * from PRIVATE_KEYS WHERE pub = ? AND source = ?', [pub, source]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (keyObject.length != 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(409); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.send({ message: `Error: Duplicated Key for source: ${source} and pub: ${pub}` }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// db script to fetch kms key from the database, if any exist | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let kmsKey = await db.fetchOne('SELECT kmsKey from PRIVATE_KEYS WHERE provider = ? LIMIT 1', ['mock']) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!kmsKey) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
kmsKey = await kms.createKmsKey({}).then((kmsRes) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ('code' in kmsRes) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(kmsRes.code); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.send({ message: 'Internal server error. Failed to create top-level kms key in KMS' }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return kmsRes.kmsKey; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+107
to
+114
Check warningCode scanning / CodeQL Useless assignment to local variable Warning
The value assigned to kmsKey here is unused.
Copilot AutofixAI about 8 hours ago To fix the issue, we need to refactor the code to ensure that the value of
Suggested changeset
1
modules/express-kms-api-example/src/api/handlers/POST.ts
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
Positive FeedbackNegative Feedback
Refresh and try again.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// send to kms | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const kmsRes: PostKeyKmsRes | KmsErrorRes = await kms.postKey("", prv, {}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ('code' in kmsRes) { // TODO: type guard | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(kmsRes.code); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.send({ message: 'Internal server error. Failed to encrypt prvaite key in KMS' }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// insert into database | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// TODO: better catching | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await db.run('INSERT INTO PRIVATE_KEYS values (?, ?, ?, ?, ?, ?, ?)', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pub, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
source, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
kmsRes.encryptedPrv, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
kms.providerName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
kmsRes.topLevelKeyId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
coin, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]).catch((err) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(500); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.send({ message: 'Internal server error' }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; // TODO: test this | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(200); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.json({ coin, source, type, pub }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
next(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { z } from 'zod'; | ||
import { KeySource, KeyType, MultiSigCoins } from './types'; | ||
|
||
export const ZodPostKeySchema = z.object({ | ||
prv: z.string(), // TODO: min/max length? | ||
pub: z.string(), // TODO: min/max length? | ||
coin: z.enum(MultiSigCoins), | ||
source: z.enum(KeySource), | ||
type: z.enum(KeyType), | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// TODO: add the full list of supported coins | ||
export const MultiSigCoins = ['btc', 'heth'] as const; | ||
export const KeySource = ['user', 'backup'] as const; | ||
export const KeyType = ['independent', 'tss'] as const; | ||
|
||
export type MultiSigCoinsType = (typeof MultiSigCoins)[number]; | ||
export type KeySourceType = (typeof KeySource)[number]; | ||
export type KeyTypeType = (typeof KeyType)[number]; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import bodyParser from 'body-parser'; | ||
import express from 'express'; | ||
import swaggerJSDoc from 'swagger-jsdoc'; | ||
import swaggerUi from 'swagger-ui-express'; | ||
import { GET as keyGET } from './api/handlers/GET'; | ||
import { POST as keyPOST } from './api/handlers/POST'; | ||
import { checkApiKeyMiddleware } from './middlewares/authApiKeys'; | ||
import { swaggerOptions } from './swagger'; | ||
import { mockKmsProvider } from './providers/mock/mock-kms'; | ||
import db from './db'; | ||
|
||
// TODO: move to proper .env | ||
// Add note about the port to the README | ||
// Or hardcode it | ||
const app = express(); | ||
const PORT = '3000'; | ||
const kmsInterface = new mockKmsProvider(); // TODO: use a config file to determine the provider, perhaps globally? | ||
|
||
const swaggerSpec = swaggerJSDoc(swaggerOptions); | ||
|
||
app.use(bodyParser.json()); | ||
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); | ||
app.use(checkApiKeyMiddleware); | ||
|
||
// TODO: create router for keys controllers, | ||
// I added the controllers calls directly here. | ||
app.post('/key', (req, res, next) => keyPOST(req, res, next, kmsInterface)); | ||
app.get('/key/:pub', (req, res, next) => keyGET(req, res, next, kmsInterface)); | ||
app.get('/openapi.json', (req, res) => { | ||
res.setHeader('Content-Type', 'application/json'); | ||
res.send(swaggerSpec); | ||
}); | ||
|
||
app.listen(PORT, () => { | ||
db.setup(); | ||
console.log(`KMS API example listening on port ${PORT}`); | ||
}); |
Check notice
Code scanning / CodeQL
Semicolon insertion Note
Copilot Autofix
AI about 8 hours ago
To fix the issue, explicitly add a semicolon at the end of the
res.send
statement on line 78. This ensures consistency with the rest of the function, where all other statements explicitly terminate with semicolons. No additional imports, methods, or definitions are required for this fix.