add integ tests for fetching/secrets secrets with jwt/service token

This commit is contained in:
Maidul Islam
2023-04-11 16:51:50 -07:00
parent 689ac6a8fe
commit bec80de174
11 changed files with 398 additions and 41 deletions

View File

@@ -0,0 +1,56 @@
[
{
"method": "POST",
"secret": {
"workspace": "63cefb15c8d3175601cfa989",
"type": "shared",
"tags": [],
"environment": "dev",
"secretKeyCiphertext": "eaX9a2g=",
"secretKeyIV": "YJ4adgI/wEHifGdtT9reaA==",
"secretKeyTag": "dP73x3wrq7pqxzAHo+bfPA==",
"secretValueCiphertext": "cw==",
"secretValueIV": "7ksYWWZ3+9rzLG5NpEbEgg==",
"secretValueTag": "H0YQ8vrhiVJ0XSW4nBJdQA==",
"secretCommentCiphertext": "",
"secretCommentIV": "yXhMdLdA9q7Vaw4UUaeBYA==",
"secretCommentTag": "qMj7SHESM5Jn+C2qpbw2pA=="
}
},
{
"method": "POST",
"secret": {
"workspace": "63cefb15c8d3175601cfa989",
"type": "shared",
"tags": [],
"environment": "dev",
"secretKeyCiphertext": "eaX9a2g=",
"secretKeyIV": "YJ4adgI/wEHifGdtT9reaA==",
"secretKeyTag": "dP73x3wrq7pqxzAHo+bfPA==",
"secretValueCiphertext": "cw==",
"secretValueIV": "7ksYWWZ3+9rzLG5NpEbEgg==",
"secretValueTag": "H0YQ8vrhiVJ0XSW4nBJdQA==",
"secretCommentCiphertext": "",
"secretCommentIV": "yXhMdLdA9q7Vaw4UUaeBYA==",
"secretCommentTag": "qMj7SHESM5Jn+C2qpbw2pA=="
}
},
{
"method": "POST",
"secret": {
"workspace": "63cefb15c8d3175601cfa989",
"type": "shared",
"tags": [],
"environment": "dev",
"secretKeyCiphertext": "eaX9a2g=",
"secretKeyIV": "YJ4adgI/wEHifGdtT9reaA==",
"secretKeyTag": "dP73x3wrq7pqxzAHo+bfPA==",
"secretValueCiphertext": "cw==",
"secretValueIV": "7ksYWWZ3+9rzLG5NpEbEgg==",
"secretValueTag": "H0YQ8vrhiVJ0XSW4nBJdQA==",
"secretCommentCiphertext": "",
"secretCommentIV": "yXhMdLdA9q7Vaw4UUaeBYA==",
"secretCommentTag": "qMj7SHESM5Jn+C2qpbw2pA=="
}
}
]

View File

@@ -0,0 +1,91 @@
// Helper functions for integration tests
import { Secret } from "../../src/models";
import { testUserEmail, testUserPassword } from "../../src/utils/addDevelopmentUser";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const crypto = require('crypto')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const jsrp = require('jsrp');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const axios = require('axios');
import { plainTextWorkspaceKey, testWorkspaceId } from "../../src/utils/addDevelopmentUser";
import { encryptSymmetric } from "../../src/utils/crypto";
interface TokenData {
token: string;
publicKey: string;
encryptedPrivateKey: string;
iv: string;
tag: string;
}
export const getJWTFromTestUser = (): Promise<TokenData> => {
return new Promise((resolve, reject) => {
const client = new jsrp.client();
const EMAIL = testUserEmail
const PASSWORD = testUserPassword
client.init({
username: EMAIL,
password: PASSWORD,
}, async () => {
const clientPublicKey = client.getPublicKey();
// POST: /login1
const reqBody = {
email: EMAIL,
clientPublicKey
}
const loginOneRes = await axios.post('http://localhost:4000/api/v1/auth/login1', reqBody);
const serverPublicKey = loginOneRes.data.serverPublicKey;
const salt = loginOneRes.data.salt;
client.setSalt(salt);
client.setServerPublicKey(serverPublicKey);
const clientSharedKey = client.getSharedKey(); // shared Key
const clientProof = client.getProof(); // called M1
// POST: /login2
const reqBody2 = {
email: EMAIL,
clientProof
}
const response2 = await axios.post('http://localhost:4000/api/v1/auth/login2', reqBody2);
resolve(response2.data)
})
});
}
export const getServiceTokenFromTestUser = async () => {
const loggedInUserDetails = await getJWTFromTestUser()
const randomBytes = crypto.randomBytes(16).toString('hex');
const { ciphertext, iv, tag } = encryptSymmetric({
plaintext: plainTextWorkspaceKey,
key: randomBytes,
});
const newServiceToken = await axios.post('http://localhost:4000/api/v2/service-token/', {
'name': "test service token",
'workspaceId': testWorkspaceId,
'environment': "dev",
'encryptedKey': ciphertext,
'iv': iv,
'tag': tag,
'expiresIn': Date.now() + 90000,
'permissions': ["read"]
}, {
headers: {
'Authorization': `Bearer ${loggedInUserDetails.token}`
}
});
return `${newServiceToken.data.serviceToken}.${randomBytes}`
}
export const deleteAllSecrets = async () => {
await Secret.deleteMany()
}

View File

@@ -0,0 +1,198 @@
import request from 'supertest'
import main from '../../../../src/index'
import { testWorkspaceId } from '../../../../src/utils/addDevelopmentUser';
import { deleteAllSecrets, getJWTFromTestUser, getServiceTokenFromTestUser } from '../../../helper/helper';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const batchSecretRequest = require('../../../data/batch-secrets.json');
let server: any;
beforeAll(async () => {
server = await main;
});
afterAll(async () => {
server.close();
});
describe("GET /api/v2/secrets", () => {
describe("Get secrets via JTW with no personal secrets", () => {
test("should respond with a 200 status code", async () => {
try {
// get login details
const loginResponse = await getJWTFromTestUser()
// create creates
const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`)
.send({
workspaceId: testWorkspaceId,
environment: "dev",
requests: batchSecretRequest
})
expect(createSecretsResponse.statusCode).toBe(200)
const getSecrets = await request(server)
.get("/api/v2/secrets")
.set('Authorization', `Bearer ${loginResponse.token}`)
.query({
workspaceId: testWorkspaceId,
environment: "dev"
})
expect(getSecrets.statusCode).toBe(200)
expect(getSecrets.body).toHaveProperty("secrets")
expect(getSecrets.body.secrets).toHaveLength(3)
expect(getSecrets.body.secrets).toBeInstanceOf(Array);
getSecrets.body.secrets.forEach((secret: any) => {
expect(secret).toHaveProperty('_id');
expect(secret._id).toBeTruthy();
expect(secret).toHaveProperty('version');
expect(secret.version).toBeTruthy();
expect(secret).toHaveProperty('workspace');
expect(secret.workspace).toBeTruthy();
expect(secret).toHaveProperty('type');
expect(secret.type).toBeTruthy();
expect(secret).toHaveProperty('tags');
expect(secret.tags).toHaveLength(0);
expect(secret).toHaveProperty('environment');
expect(secret.environment).toEqual("dev");
expect(secret).toHaveProperty('secretKeyCiphertext');
expect(secret.secretKeyCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretKeyIV');
expect(secret.secretKeyIV).toBeTruthy();
expect(secret).toHaveProperty('secretKeyTag');
expect(secret.secretKeyTag).toBeTruthy();
expect(secret).toHaveProperty('secretValueCiphertext');
expect(secret.secretValueCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretValueIV');
expect(secret.secretValueIV).toBeTruthy();
expect(secret).toHaveProperty('secretValueTag');
expect(secret.secretValueTag).toBeTruthy();
expect(secret).toHaveProperty('secretCommentCiphertext');
expect(secret.secretCommentCiphertext).toBeFalsy();
expect(secret).toHaveProperty('secretCommentIV');
expect(secret.secretCommentIV).toBeTruthy();
expect(secret).toHaveProperty('secretCommentTag');
expect(secret.secretCommentTag).toBeTruthy();
expect(secret).toHaveProperty('createdAt');
expect(secret.createdAt).toBeTruthy();
expect(secret).toHaveProperty('updatedAt');
expect(secret.updatedAt).toBeTruthy();
});
} finally {
// clean up
await deleteAllSecrets()
}
})
})
describe("fetch secrets via service token with no personal secrets", () => {
test("should respond with a 200 status code", async () => {
// get login details
const loginResponse = await getJWTFromTestUser()
// create creates
const createSecretsResponse = await request(server)
.post("/api/v2/secrets/batch")
.set('Authorization', `Bearer ${loginResponse.token}`)
.send({
workspaceId: testWorkspaceId,
environment: "dev",
requests: batchSecretRequest
})
expect(createSecretsResponse.statusCode).toBe(200)
// now use the service token to fetch secrets
const serviceToken = await getServiceTokenFromTestUser()
const getSecrets = await request(server)
.get("/api/v2/secrets")
.set('Authorization', `Bearer ${serviceToken}`)
.query({
workspaceId: testWorkspaceId,
environment: "dev"
})
expect(getSecrets.statusCode).toBe(200)
expect(getSecrets.body).toHaveProperty("secrets")
expect(getSecrets.body.secrets).toHaveLength(3)
expect(getSecrets.body.secrets).toBeInstanceOf(Array);
getSecrets.body.secrets.forEach((secret: any) => {
expect(secret).toHaveProperty('_id');
expect(secret._id).toBeTruthy();
expect(secret).toHaveProperty('version');
expect(secret.version).toBeTruthy();
expect(secret).toHaveProperty('workspace');
expect(secret.workspace).toBeTruthy();
expect(secret).toHaveProperty('type');
expect(secret.type).toBeTruthy();
expect(secret).toHaveProperty('tags');
expect(secret.tags).toHaveLength(0);
expect(secret).toHaveProperty('environment');
expect(secret.environment).toEqual("dev");
expect(secret).toHaveProperty('secretKeyCiphertext');
expect(secret.secretKeyCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretKeyIV');
expect(secret.secretKeyIV).toBeTruthy();
expect(secret).toHaveProperty('secretKeyTag');
expect(secret.secretKeyTag).toBeTruthy();
expect(secret).toHaveProperty('secretValueCiphertext');
expect(secret.secretValueCiphertext).toBeTruthy();
expect(secret).toHaveProperty('secretValueIV');
expect(secret.secretValueIV).toBeTruthy();
expect(secret).toHaveProperty('secretValueTag');
expect(secret.secretValueTag).toBeTruthy();
expect(secret).toHaveProperty('secretCommentCiphertext');
expect(secret.secretCommentCiphertext).toBeFalsy();
expect(secret).toHaveProperty('secretCommentIV');
expect(secret.secretCommentIV).toBeTruthy();
expect(secret).toHaveProperty('secretCommentTag');
expect(secret.secretCommentTag).toBeTruthy();
expect(secret).toHaveProperty('createdAt');
expect(secret.createdAt).toBeTruthy();
expect(secret).toHaveProperty('updatedAt');
expect(secret.updatedAt).toBeTruthy();
});
})
})
})

View File

@@ -4,7 +4,7 @@ import {
decryptSymmetric,
encryptAsymmetric,
encryptSymmetric
} from '../../src/utils/crypto';
} from '../../../src/utils/crypto';
describe('Crypto', () => {
describe('encryptAsymmetric', () => {

View File

@@ -1,5 +1,5 @@
import { describe, test, expect } from '@jest/globals';
import { getChannelFromUserAgent } from '../../src/utils/posthog';
import { getChannelFromUserAgent } from '../../../src/utils/posthog';
describe('posthog getChannelFromUserAgent', () => {
test("should return 'web' when userAgent includes 'mozilla'", () => {