ref: working on connected accounts
This commit is contained in:
parent
02949fa615
commit
ee48abb737
@ -2,7 +2,7 @@ import fastify from "fastify";
|
|||||||
import { log, logger } from "@/utils/log";
|
import { log, logger } from "@/utils/log";
|
||||||
import { serializerCompiler, validatorCompiler, ZodTypeProvider } from "fastify-type-provider-zod";
|
import { serializerCompiler, validatorCompiler, ZodTypeProvider } from "fastify-type-provider-zod";
|
||||||
import { onShutdown } from "@/utils/shutdown";
|
import { onShutdown } from "@/utils/shutdown";
|
||||||
import { EventRouter } from "@/modules/eventRouter";
|
import { EventRouter } from "@/app/events/eventRouter";
|
||||||
import { Fastify } from "./types";
|
import { Fastify } from "./types";
|
||||||
import { authRoutes } from "./routes/authRoutes";
|
import { authRoutes } from "./routes/authRoutes";
|
||||||
import { pushRoutes } from "./routes/pushRoutes";
|
import { pushRoutes } from "./routes/pushRoutes";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { EventRouter, buildUpdateAccountUpdate } from "@/modules/eventRouter";
|
import { EventRouter, buildUpdateAccountUpdate } from "@/app/events/eventRouter";
|
||||||
import { db } from "@/storage/db";
|
import { db } from "@/storage/db";
|
||||||
import { Fastify } from "../types";
|
import { Fastify } from "../types";
|
||||||
import { getPublicUrl } from "@/storage/files";
|
import { getPublicUrl } from "@/storage/files";
|
||||||
@ -6,6 +6,7 @@ import { z } from "zod";
|
|||||||
import { randomKeyNaked } from "@/utils/randomKeyNaked";
|
import { randomKeyNaked } from "@/utils/randomKeyNaked";
|
||||||
import { allocateUserSeq } from "@/storage/seq";
|
import { allocateUserSeq } from "@/storage/seq";
|
||||||
import { log } from "@/utils/log";
|
import { log } from "@/utils/log";
|
||||||
|
import { AccountProfile } from "@/types";
|
||||||
|
|
||||||
export function accountRoutes(app: Fastify, eventRouter: EventRouter) {
|
export function accountRoutes(app: Fastify, eventRouter: EventRouter) {
|
||||||
app.get('/v1/account/profile', {
|
app.get('/v1/account/profile', {
|
||||||
@ -21,13 +22,15 @@ export function accountRoutes(app: Fastify, eventRouter: EventRouter) {
|
|||||||
githubUser: true
|
githubUser: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const connectedVendors = new Set((await db.serviceAccountToken.findMany({ where: { accountId: userId } })).map(t => t.vendor));
|
||||||
return reply.send({
|
return reply.send({
|
||||||
id: userId,
|
id: userId,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
firstName: user.firstName,
|
firstName: user.firstName,
|
||||||
lastName: user.lastName,
|
lastName: user.lastName,
|
||||||
avatar: user.avatar ? { ...user.avatar, url: getPublicUrl(user.avatar.path) } : null,
|
avatar: user.avatar ? { ...user.avatar, url: getPublicUrl(user.avatar.path) } : null,
|
||||||
github: user.githubUser ? user.githubUser.profile : null
|
github: user.githubUser ? user.githubUser.profile : null,
|
||||||
|
connectedServices: Array.from(connectedVendors)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,12 +6,12 @@ import { db } from "@/storage/db";
|
|||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { allocateUserSeq } from "@/storage/seq";
|
import { allocateUserSeq } from "@/storage/seq";
|
||||||
import { randomKeyNaked } from "@/utils/randomKeyNaked";
|
import { randomKeyNaked } from "@/utils/randomKeyNaked";
|
||||||
import { buildUpdateAccountUpdate } from "@/modules/eventRouter";
|
import { buildUpdateAccountUpdate } from "@/app/events/eventRouter";
|
||||||
import { GitHubProfile } from "../types";
|
import { GitHubProfile } from "../types";
|
||||||
import { separateName } from "@/utils/separateName";
|
import { separateName } from "@/utils/separateName";
|
||||||
import { uploadImage } from "@/storage/uploadImage";
|
import { uploadImage } from "@/storage/uploadImage";
|
||||||
import { EventRouter } from "@/modules/eventRouter";
|
import { EventRouter } from "@/app/events/eventRouter";
|
||||||
import { encryptString } from "@/modules/encrypt";
|
import { decryptString, encryptString } from "@/modules/encrypt";
|
||||||
|
|
||||||
export function connectRoutes(app: Fastify, eventRouter: EventRouter) {
|
export function connectRoutes(app: Fastify, eventRouter: EventRouter) {
|
||||||
|
|
||||||
@ -359,4 +359,95 @@ export function connectRoutes(app: Fastify, eventRouter: EventRouter) {
|
|||||||
return reply.code(500).send({ error: 'Failed to disconnect GitHub account' });
|
return reply.code(500).send({ error: 'Failed to disconnect GitHub account' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// Inference endpoints
|
||||||
|
//
|
||||||
|
|
||||||
|
app.post('/v1/connect/:vendor/register', {
|
||||||
|
preHandler: app.authenticate,
|
||||||
|
schema: {
|
||||||
|
body: z.object({
|
||||||
|
token: z.string()
|
||||||
|
}),
|
||||||
|
params: z.object({
|
||||||
|
vendor: z.enum(['openai', 'anthropic', 'gemini'])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, async (request, reply) => {
|
||||||
|
const userId = request.userId;
|
||||||
|
const encrypted = encryptString(['user', userId, 'vendors', request.params.vendor, 'token'], request.body.token);
|
||||||
|
await db.serviceAccountToken.upsert({
|
||||||
|
where: { accountId_vendor: { accountId: userId, vendor: request.params.vendor } },
|
||||||
|
update: { updatedAt: new Date(), token: encrypted },
|
||||||
|
create: { accountId: userId, vendor: request.params.vendor, token: encrypted }
|
||||||
|
});
|
||||||
|
reply.send({ success: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/v1/connect/:vendor/token', {
|
||||||
|
preHandler: app.authenticate,
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
vendor: z.enum(['openai', 'anthropic', 'gemini'])
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
token: z.string().nullable()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, async (request, reply) => {
|
||||||
|
const userId = request.userId;
|
||||||
|
const token = await db.serviceAccountToken.findUnique({
|
||||||
|
where: { accountId_vendor: { accountId: userId, vendor: request.params.vendor } },
|
||||||
|
select: { token: true }
|
||||||
|
});
|
||||||
|
if (!token) {
|
||||||
|
return reply.send({ token: null });
|
||||||
|
} else {
|
||||||
|
return reply.send({ token: decryptString(['user', userId, 'vendors', request.params.vendor, 'token'], token.token) });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.delete('/v1/connect/:vendor', {
|
||||||
|
preHandler: app.authenticate,
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
vendor: z.enum(['openai', 'anthropic', 'gemini'])
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
success: z.literal(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, async (request, reply) => {
|
||||||
|
const userId = request.userId;
|
||||||
|
await db.serviceAccountToken.delete({ where: { accountId_vendor: { accountId: userId, vendor: request.params.vendor } } });
|
||||||
|
reply.send({ success: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/v1/connect/tokens', {
|
||||||
|
preHandler: app.authenticate,
|
||||||
|
schema: {
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
tokens: z.array(z.object({
|
||||||
|
vendor: z.string(),
|
||||||
|
token: z.string()
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, async (request, reply) => {
|
||||||
|
const userId = request.userId;
|
||||||
|
const tokens = await db.serviceAccountToken.findMany({ where: { accountId: userId } });
|
||||||
|
let decrypted = [];
|
||||||
|
for (const token of tokens) {
|
||||||
|
decrypted.push({ vendor: token.vendor, token: decryptString(['user', userId, 'vendors', token.vendor, 'token'], token.token) });
|
||||||
|
}
|
||||||
|
return reply.send({ tokens: decrypted });
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
@ -1,11 +1,11 @@
|
|||||||
import { EventRouter } from "@/modules/eventRouter";
|
import { EventRouter } from "@/app/events/eventRouter";
|
||||||
import { Fastify } from "../types";
|
import { Fastify } from "../types";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@/storage/db";
|
import { db } from "@/storage/db";
|
||||||
import { log } from "@/utils/log";
|
import { log } from "@/utils/log";
|
||||||
import { randomKeyNaked } from "@/utils/randomKeyNaked";
|
import { randomKeyNaked } from "@/utils/randomKeyNaked";
|
||||||
import { allocateUserSeq } from "@/storage/seq";
|
import { allocateUserSeq } from "@/storage/seq";
|
||||||
import { buildUpdateMachineUpdate } from "@/modules/eventRouter";
|
import { buildUpdateMachineUpdate } from "@/app/events/eventRouter";
|
||||||
|
|
||||||
export function machinesRoutes(app: Fastify, eventRouter: EventRouter) {
|
export function machinesRoutes(app: Fastify, eventRouter: EventRouter) {
|
||||||
app.post('/v1/machines', {
|
app.post('/v1/machines', {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { EventRouter, buildNewSessionUpdate } from "@/modules/eventRouter";
|
import { EventRouter, buildNewSessionUpdate } from "@/app/events/eventRouter";
|
||||||
import { type Fastify } from "../types";
|
import { type Fastify } from "../types";
|
||||||
import { db } from "@/storage/db";
|
import { db } from "@/storage/db";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { onShutdown } from "@/utils/shutdown";
|
import { onShutdown } from "@/utils/shutdown";
|
||||||
import { Fastify } from "./types";
|
import { Fastify } from "./types";
|
||||||
import { buildMachineActivityEphemeral, ClientConnection, EventRouter } from "@/modules/eventRouter";
|
import { buildMachineActivityEphemeral, ClientConnection, EventRouter } from "@/app/events/eventRouter";
|
||||||
import { Server, Socket } from "socket.io";
|
import { Server, Socket } from "socket.io";
|
||||||
import { log } from "@/utils/log";
|
import { log } from "@/utils/log";
|
||||||
import { auth } from "@/app/auth/auth";
|
import { auth } from "@/app/auth/auth";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { machineAliveEventsCounter, websocketEventsCounter } from "@/app/monitoring/metrics2";
|
import { machineAliveEventsCounter, websocketEventsCounter } from "@/app/monitoring/metrics2";
|
||||||
import { activityCache } from "@/app/presence/sessionCache";
|
import { activityCache } from "@/app/presence/sessionCache";
|
||||||
import { buildMachineActivityEphemeral, buildUpdateMachineUpdate, EventRouter } from "@/modules/eventRouter";
|
import { buildMachineActivityEphemeral, buildUpdateMachineUpdate, EventRouter } from "@/app/events/eventRouter";
|
||||||
import { log } from "@/utils/log";
|
import { log } from "@/utils/log";
|
||||||
import { db } from "@/storage/db";
|
import { db } from "@/storage/db";
|
||||||
import { Socket } from "socket.io";
|
import { Socket } from "socket.io";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { EventRouter } from "@/modules/eventRouter";
|
import { EventRouter } from "@/app/events/eventRouter";
|
||||||
import { log } from "@/utils/log";
|
import { log } from "@/utils/log";
|
||||||
import { Socket } from "socket.io";
|
import { Socket } from "socket.io";
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { sessionAliveEventsCounter, websocketEventsCounter } from "@/app/monitoring/metrics2";
|
import { sessionAliveEventsCounter, websocketEventsCounter } from "@/app/monitoring/metrics2";
|
||||||
import { activityCache } from "@/app/presence/sessionCache";
|
import { activityCache } from "@/app/presence/sessionCache";
|
||||||
import { buildNewMessageUpdate, buildSessionActivityEphemeral, buildUpdateSessionUpdate, ClientConnection, EventRouter } from "@/modules/eventRouter";
|
import { buildNewMessageUpdate, buildSessionActivityEphemeral, buildUpdateSessionUpdate, ClientConnection, EventRouter } from "@/app/events/eventRouter";
|
||||||
import { db } from "@/storage/db";
|
import { db } from "@/storage/db";
|
||||||
import { allocateSessionSeq, allocateUserSeq } from "@/storage/seq";
|
import { allocateSessionSeq, allocateUserSeq } from "@/storage/seq";
|
||||||
import { AsyncLock } from "@/utils/lock";
|
import { AsyncLock } from "@/utils/lock";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Socket } from "socket.io";
|
import { Socket } from "socket.io";
|
||||||
import { AsyncLock } from "@/utils/lock";
|
import { AsyncLock } from "@/utils/lock";
|
||||||
import { db } from "@/storage/db";
|
import { db } from "@/storage/db";
|
||||||
import { buildUsageEphemeral, EventRouter } from "@/modules/eventRouter";
|
import { buildUsageEphemeral, EventRouter } from "@/app/events/eventRouter";
|
||||||
import { log } from "@/utils/log";
|
import { log } from "@/utils/log";
|
||||||
|
|
||||||
export function usageHandler(userId: string, socket: Socket, eventRouter: EventRouter) {
|
export function usageHandler(userId: string, socket: Socket, eventRouter: EventRouter) {
|
||||||
|
@ -2,7 +2,7 @@ import { db } from "@/storage/db";
|
|||||||
import { delay } from "@/utils/delay";
|
import { delay } from "@/utils/delay";
|
||||||
import { forever } from "@/utils/forever";
|
import { forever } from "@/utils/forever";
|
||||||
import { shutdownSignal } from "@/utils/shutdown";
|
import { shutdownSignal } from "@/utils/shutdown";
|
||||||
import { buildMachineActivityEphemeral, buildSessionActivityEphemeral, EventRouter } from "@/modules/eventRouter";
|
import { buildMachineActivityEphemeral, buildSessionActivityEphemeral, EventRouter } from "@/app/events/eventRouter";
|
||||||
|
|
||||||
export function startTimeout(eventRouter: EventRouter) {
|
export function startTimeout(eventRouter: EventRouter) {
|
||||||
forever('session-timeout', async () => {
|
forever('session-timeout', async () => {
|
||||||
|
@ -11,7 +11,7 @@ import { startDatabaseMetricsUpdater } from "@/app/monitoring/metrics2";
|
|||||||
import { initEncrypt } from "./modules/encrypt";
|
import { initEncrypt } from "./modules/encrypt";
|
||||||
import { initGithub } from "./modules/github";
|
import { initGithub } from "./modules/github";
|
||||||
import { loadFiles } from "./storage/files";
|
import { loadFiles } from "./storage/files";
|
||||||
import { EventRouter } from "./modules/eventRouter";
|
import { EventRouter } from "./app/events/eventRouter";
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ export function encryptBytes(path: string[], bytes: Uint8Array) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function decryptString(path: string[], encrypted: Uint8Array) {
|
export function decryptString(path: string[], encrypted: Uint8Array) {
|
||||||
return keyTree!.symmetricDecryptBuffer(path, encrypted);
|
return keyTree!.symmetricDecryptString(path, encrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decryptBytes(path: string[], encrypted: Uint8Array) {
|
export function decryptBytes(path: string[], encrypted: Uint8Array) {
|
||||||
|
@ -10,4 +10,5 @@ export type AccountProfile = {
|
|||||||
value: string | null;
|
value: string | null;
|
||||||
version: number;
|
version: number;
|
||||||
} | null;
|
} | null;
|
||||||
|
connectedServices: string[];
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user