41 create tenant twilio config #62
5 changed files with 71 additions and 3 deletions
11
.env
11
.env
|
|
@ -1,9 +1,14 @@
|
||||||
NODE_ENV=
|
NODE_ENV=
|
||||||
|
|
||||||
# TWILIO
|
# TWILIO
|
||||||
TWILIO_ACCOUNT_SID=
|
TWILIO_ACCOUNT_SID=secret_do_not_commit_or_change_this_create_.env.local_instead
|
||||||
TWILIO_AUTH_TOKEN=
|
TWILIO_AUTH_TOKEN=secret_do_not_commit_or_change_this_create_.env.local_instead
|
||||||
TWILIO_PHONE_NUMBER=
|
TWILIO_PHONE_NUMBER=secret_do_not_commit_or_change_this_create_.env.local_instead
|
||||||
|
|
||||||
|
# SECRETS
|
||||||
|
SECRETS_PASSWORD=secret_do_not_commit_or_change_this_create_.env.local_instead
|
||||||
|
SECRETS_SALT=secret_do_not_commit_or_change_this_create_.env.local_instead
|
||||||
|
SECRETS_IV_POSITION=secret_do_not_commit_or_change_this_create_.env.local_instead
|
||||||
|
|
||||||
# PRISMA
|
# PRISMA
|
||||||
DATABASE_URL="postgres://hestia:test123@localhost:5432/hestia"
|
DATABASE_URL="postgres://hestia:test123@localhost:5432/hestia"
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ const ValidateEnvironment = () => {
|
||||||
TWILIO_ACCOUNT_SID: z.string().min(1),
|
TWILIO_ACCOUNT_SID: z.string().min(1),
|
||||||
TWILIO_AUTH_TOKEN: z.string().min(1),
|
TWILIO_AUTH_TOKEN: z.string().min(1),
|
||||||
TWILIO_PHONE_NUMBER: z.string().regex(PhoneRegex),
|
TWILIO_PHONE_NUMBER: z.string().regex(PhoneRegex),
|
||||||
|
SECRETS_PASSWORD: z.string().length(32),
|
||||||
|
SECRETS_SALT: z.string().min(16),
|
||||||
|
SECRETS_IV_POSITION: z.number().positive(),
|
||||||
})
|
})
|
||||||
.safeParse(process.env);
|
.safeParse(process.env);
|
||||||
|
|
||||||
|
|
|
||||||
20
src/lib/server/crypto/encryption.test.ts
Normal file
20
src/lib/server/crypto/encryption.test.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { describe, expect, it, vi } from 'vitest';
|
||||||
|
import { decrypt, encrypt } from './encryption';
|
||||||
|
|
||||||
|
describe('Encryption', () => {
|
||||||
|
it('should encrypt and decrypt data', () => {
|
||||||
|
const data = 'aye its ya boi!';
|
||||||
|
|
||||||
|
vi.mock('$env/static/private', () => ({
|
||||||
|
SECRETS_PASSWORD: 'aac7405eb3384e68c285fc252dbf68b2',
|
||||||
|
SECRETS_SALT: 'c4aeaf8bda72ea45e8c23269ca849013',
|
||||||
|
SECRETS_IV_POSITION: 9,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const encrypted = encrypt(data);
|
||||||
|
console.log(encrypted);
|
||||||
|
const decrypted = decrypt(encrypted);
|
||||||
|
|
||||||
|
expect(decrypted).toEqual(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
39
src/lib/server/crypto/encryption.ts
Normal file
39
src/lib/server/crypto/encryption.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { SECRETS_PASSWORD, SECRETS_IV_POSITION, SECRETS_SALT } from '$env/static/private';
|
||||||
|
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';
|
||||||
|
|
||||||
|
const algorithm = 'aes-256-gcm';
|
||||||
|
const password = SECRETS_PASSWORD;
|
||||||
|
const salt = SECRETS_SALT;
|
||||||
|
const iv_position = Number(SECRETS_IV_POSITION);
|
||||||
|
|
||||||
|
function construct(encrypted: string, tag: Buffer, iv: { value: Buffer; position: number }) {
|
||||||
|
return `${encrypted.slice(0, iv.position)}${iv.value.toString('hex')}${encrypted.slice(iv.position)}${tag.toString('hex')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deconstruct(encrypted: string, position: number): [Buffer, string, Buffer] {
|
||||||
|
const iv = encrypted.slice(position, position + 16);
|
||||||
|
const text = `${encrypted.slice(0, position)}${encrypted.slice(position + 16, encrypted.length - 32)}`;
|
||||||
|
const authTag = encrypted.slice(encrypted.length - 32);
|
||||||
|
return [Buffer.from(iv, 'hex'), text, Buffer.from(authTag, 'hex')];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function encrypt(value: string): string {
|
||||||
|
const key = scryptSync(password, salt, 32);
|
||||||
|
const iv = randomBytes(8);
|
||||||
|
|
||||||
|
const cipher = createCipheriv(algorithm, key, iv);
|
||||||
|
const encrypted = cipher.update(value, 'utf-8', 'hex') + cipher.final('hex');
|
||||||
|
const authTag = cipher.getAuthTag();
|
||||||
|
|
||||||
|
return construct(encrypted, authTag, { value: iv, position: iv_position });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decrypt(value: string): string {
|
||||||
|
const key = scryptSync(password, salt, 32);
|
||||||
|
const [iv, text, authTag] = deconstruct(value, iv_position);
|
||||||
|
|
||||||
|
const decipher = createDecipheriv(algorithm, key, iv);
|
||||||
|
decipher.setAuthTag(authTag);
|
||||||
|
|
||||||
|
return decipher.update(text, 'hex', 'utf-8') + decipher.final('utf-8');
|
||||||
|
}
|
||||||
1
src/lib/server/crypto/index.ts
Normal file
1
src/lib/server/crypto/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './encryption';
|
||||||
Loading…
Add table
Reference in a new issue