Begin api-key functionality on backend

This commit is contained in:
Tuan Dang
2022-12-25 12:45:43 -05:00
parent 2513250993
commit d869968f88
9 changed files with 658 additions and 35 deletions
+3 -2
View File
@@ -27,7 +27,8 @@ import {
password as passwordRouter,
stripe as stripeRouter,
integration as integrationRouter,
integrationAuth as integrationAuthRouter
integrationAuth as integrationAuthRouter,
apiKey as apiKeyRouter
} from './routes';
import { getLogger } from './utils/logger';
import { RouteNotFoundError } from './utils/errors';
@@ -74,7 +75,7 @@ app.use('/api/v1/password', passwordRouter);
app.use('/api/v1/stripe', stripeRouter);
app.use('/api/v1/integration', integrationRouter);
app.use('/api/v1/integration-auth', integrationAuthRouter);
app.use('/api/v1/api-key', apiKeyRouter);
//* Handle unrouted requests and respond with proper error message as well as status code
app.use((req, res, next)=>{
@@ -74,3 +74,12 @@ export const createServiceToken = async (req: Request, res: Response) => {
token
});
};
/**
* SERVICE_TOKEN: <JWT_SERVICE_TOKEN>,<PRIVATE_KEY_SERVICE_TOKEN>
* - <JWT_SERVICE_TOKEN> authorizes the service token for "service token"-only endpoints.
* - <PRIVATE_KEY_SERVICE_TOKEN> authorizes the service token to pull secrets via that endpoint.
*
*
*
*/
+63
View File
@@ -0,0 +1,63 @@
import { Schema, model, Types } from 'mongoose';
import { ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD } from '../variables';
// TODO: add scopes
export interface IAPIKey {
name: string;
workspace: string;
environment: string;
expiresAt: Date;
prefix: string;
apiKeyHash: string;
encryptedKey: string;
iv: string;
tag: string;
}
const apiKeySchema = new Schema<IAPIKey>(
{
name: {
type: String,
required: true
},
workspace: {
type: String
},
environment: {
type: String,
enum: [ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD]
},
expiresAt: {
type: Date
},
prefix: {
type: String,
required: true
},
apiKeyHash: {
type: String,
unique: true,
required: true
},
encryptedKey: {
type: String,
select: true
},
iv: {
type: String,
select: true
},
tag: {
type: String,
select: true
}
},
{
timestamps: true
}
);
const APIKey = model<IAPIKey>('APIKey', apiKeySchema);
export default APIKey;
+4 -1
View File
@@ -14,6 +14,7 @@ import Token, { IToken } from './token';
import User, { IUser } from './user';
import UserAction, { IUserAction } from './userAction';
import Workspace, { IWorkspace } from './workspace';
import APIKey, { IAPIKey } from './apiKey';
export {
BackupPrivateKey,
@@ -47,5 +48,7 @@ export {
UserAction,
IUserAction,
Workspace,
IWorkspace
IWorkspace,
APIKey,
IAPIKey,
};
+80
View File
@@ -0,0 +1,80 @@
import express from 'express';
const router = express.Router();
import {
requireAuth
} from '../middleware';
import {
APIKey
} from '../models';
import { body } from 'express-validator';
import crypto from 'crypto';
import bcrypt from 'bcrypt';
// import * as bcrypt from 'bcrypt';
// const bcrypt = require('bcrypt');
import * as Sentry from '@sentry/node';
// POST /api/v1/api-key
router.post(
'/',
requireAuth,
body('name').exists().trim(),
body('workspace'),
body('environment'),
body('encryptedKey'),
body('iv'),
body('tag'),
body('expiresAt'),
async (req, res) => {
let savedAPIKey;
try {
const {
name,
workspace,
environment,
encryptedKey,
iv,
tag,
expiresAt
} = req.body;
// api-key: 38 characters
// 6-char: prefix
// 32-char: remaining
const apiKey = crypto.randomBytes(19).toString('hex');
const saltRounds = 10; // config?
const apiKeyHash = await bcrypt.hash(apiKey, saltRounds);
savedAPIKey = await new APIKey({
name,
workspace,
environment,
expiresAt,
prefix: apiKey.substring(0, 6),
apiKeyHash,
encryptedKey,
iv,
tag
}).save();
// 1. generate api key
// 2. hash api key with bcrypt
// 3. store hash and api key info in db
// 4. return api key
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'xxx'
});
}
return res.status(200).send({
apiKey: savedAPIKey
});
}
);
// INFISICAL TOKEN = <API_KEY>.<KEY>
export default router;
+3 -1
View File
@@ -15,6 +15,7 @@ import password from './password';
import stripe from './stripe';
import integration from './integration';
import integrationAuth from './integrationAuth';
import apiKey from './apiKey';
export {
signup,
@@ -33,5 +34,6 @@ export {
password,
stripe,
integration,
integrationAuth
integrationAuth,
apiKey
};
+1 -1
View File
@@ -10,7 +10,7 @@ import { body } from 'express-validator';
import { ADMIN, MEMBER, GRANTED } from '../variables';
import { serviceTokenController } from '../controllers';
// TODO: revoke service token
// Note to devs: service-token to be deprecated in favor of api-key
router.get(
'/',