Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/trigger-tasks-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- main
paths:
- "**/src/jobs/tasks/**"
- "**/src/trigger/**"

jobs:
deploy:
Expand All @@ -28,4 +29,5 @@ jobs:
- name: 🚀 Deploy Trigger.dev
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
run: bunx trigger.dev@latest deploy
28 changes: 15 additions & 13 deletions apps/app/src/lib/encryption.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
import argon2 from "argon2";
import {
createCipheriv,
createDecipheriv,
randomBytes,
scryptSync,
} from "node:crypto";

const ALGORITHM = "aes-256-gcm";
const IV_LENGTH = 12;
Expand All @@ -14,16 +18,14 @@ export interface EncryptedData {
salt: string;
}

export async function deriveKey(secret: string, salt: Buffer): Promise<Buffer> {
const hash = await argon2.hash(secret, {
salt,
memoryCost: 19456,
timeCost: 2,
parallelism: 1,
raw: true,
// Simple key derivation using Node's built-in scrypt instead of argon2
function deriveKey(secret: string, salt: Buffer): Buffer {
return scryptSync(secret, salt, KEY_LENGTH, {
// These are reasonable defaults for scrypt
N: 16384,
r: 8,
p: 1,
});

return Buffer.from(hash);
}

export async function encrypt(text: string): Promise<EncryptedData> {
Expand All @@ -35,7 +37,7 @@ export async function encrypt(text: string): Promise<EncryptedData> {

const salt = randomBytes(SALT_LENGTH);
const iv = randomBytes(IV_LENGTH);
const key = await deriveKey(secretKey, salt);
const key = deriveKey(secretKey, salt);
const cipher = createCipheriv(ALGORITHM, key, iv);

const encrypted = Buffer.concat([
Expand Down Expand Up @@ -64,7 +66,7 @@ export async function decrypt(encryptedData: EncryptedData): Promise<string> {
const tag = Buffer.from(encryptedData.tag, "base64");
const salt = Buffer.from(encryptedData.salt, "base64");

const key = await deriveKey(secretKey, salt);
const key = deriveKey(secretKey, salt);

const decipher = createDecipheriv(ALGORITHM, key, iv);
decipher.setAuthTag(tag);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { db } from "@bubba/db";
import { logger, schemaTask } from "@trigger.dev/sdk/v3";
import axios from "axios";
import { z } from "zod";
import { Departments } from "@bubba/db";
import { decrypt } from "@/lib/encryption";

// Define the input schema for the Deel task
const deelTaskSchema = z.object({
Expand Down Expand Up @@ -127,12 +129,51 @@ export const syncDeelEmployees = schemaTask({
}

// Extract access token from user settings
const accessToken = integration.user_settings.accessToken;
if (!accessToken) {
let accessToken: string | undefined;
try {
if (
integration.user_settings.api_key &&
typeof integration.user_settings.api_key === "object" &&
"encrypted" in integration.user_settings.api_key
) {
// Decrypt the access token
try {
accessToken = await decrypt(integration.user_settings.api_key);
logger.info("Successfully decrypted Deel API key");
} catch (decryptError) {
logger.error(`Failed to decrypt Deel API key: ${decryptError}`);

// Check if SECRET_KEY is set
if (!process.env.SECRET_KEY) {
return {
success: false,
error:
"Missing SECRET_KEY environment variable required for decryption",
};
}

return {
success: false,
error:
"Failed to decrypt API key. Make sure SECRET_KEY is correct.",
};
}
} else {
// For backward compatibility, in case it's stored as a plain string
accessToken = integration.user_settings.api_key;
}

if (!accessToken) {
logger.error(
`Deel integration ${integration.name} is missing an access token`
);
return { success: false, error: "Missing access token" };
}
} catch (error) {
logger.error(
`Deel integration ${integration.name} is missing an access token`
`Failed to decrypt access token for Deel integration ${integration.name}: ${error}`
);
return { success: false, error: "Missing access token" };
return { success: false, error: "Failed to decrypt access token" };
}

// Fetch employees from Deel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const deelEmployeeSchedule = schedules.task({

const deelIntegrations = await db.organizationIntegrations.findMany({
where: {
integration_id: "Deel",
integration_id: "deel",
},
select: {
id: true,
Expand Down
50 changes: 25 additions & 25 deletions apps/app/trigger.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,29 @@ import { puppeteer } from "@trigger.dev/build/extensions/puppeteer";
import { defineConfig } from "@trigger.dev/sdk/v3";

export default defineConfig({
project: "proj_lhxjliiqgcdyqbgtucda",
runtime: "node",
logLevel: "log",
instrumentations: [new PrismaInstrumentation()],
maxDuration: 300,
build: {
extensions: [
prismaExtension({
schema: "../../packages/db/prisma/schema/schema.prisma",
}),
puppeteer(),
syncVercelEnvVars(),
],
},
retries: {
enabledInDev: true,
default: {
maxAttempts: 3,
minTimeoutInMs: 1000,
maxTimeoutInMs: 10000,
factor: 2,
randomize: true,
},
},
dirs: ["./src/jobs"],
project: "proj_lhxjliiqgcdyqbgtucda",
runtime: "node",
logLevel: "log",
instrumentations: [new PrismaInstrumentation()],
maxDuration: 300, // 5 minutes
build: {
extensions: [
prismaExtension({
schema: "../../packages/db/prisma/schema/schema.prisma",
}),
puppeteer(),
syncVercelEnvVars(),
],
},
retries: {
enabledInDev: true,
default: {
maxAttempts: 3,
minTimeoutInMs: 1000,
maxTimeoutInMs: 10000,
factor: 2,
randomize: true,
},
},
dirs: ["./src/jobs", "./src/trigger"],
});
2 changes: 1 addition & 1 deletion apps/web/trigger.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default defineConfig({
// The max compute seconds a task is allowed to run. If the task run exceeds this duration, it will be stopped.
// You can override this on an individual task.
// See https://trigger.dev/docs/runs/max-duration
maxDuration: 3600,
maxDuration: 3600, // 1 hour
retries: {
enabledInDev: true,
default: {
Expand Down