feat(infisical-pg): test first milestone one flow

This commit is contained in:
Akhil Mohan
2024-01-27 12:38:22 +05:30
parent aaba4a0895
commit 15b57de0ed
92 changed files with 3668 additions and 436 deletions
+102 -7
View File
@@ -1,47 +1,142 @@
import { Knex } from "knex";
import { z } from "zod";
import { registerV1EERoutes } from "@app/ee/routes/v1";
import { permissionDalFactory } from "@app/ee/services/permission/permission-dal";
import { permissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { getConfig } from "@app/lib/config/env";
import { apiKeyDalFactory } from "@app/services/api-key/api-key-dal";
import { apiKeyServiceFactory } from "@app/services/api-key/api-key-service";
import { authDalFactory } from "@app/services/auth/auth-dal";
import { authLoginServiceFactory } from "@app/services/auth/auth-login-service";
import { authPaswordServiceFactory } from "@app/services/auth/auth-password-service";
import { authSignupServiceFactory } from "@app/services/auth/auth-signup-service";
import { incidentContactDalFactory } from "@app/services/org/incident-contacts-dal";
import { orgDalFactory } from "@app/services/org/org-dal";
import { orgRoleDalFactory } from "@app/services/org/org-role-dal";
import { orgRoleServiceFactory } from "@app/services/org/org-role-service";
import { orgServiceFactory } from "@app/services/org/org-service";
import { serverCfgDalFactory } from "@app/services/server-cfg/server-cfg-dal";
import { serverCfgServiceFactory } from "@app/services/server-cfg/server-cfg-service";
import { TSmtpService } from "@app/services/smtp/smtp-service";
import { tokenDalFactory } from "@app/services/token/token-dal";
import { tokenServiceFactory } from "@app/services/token/token-service";
import { userDalFactory } from "@app/services/user/user-dal";
import { userServiceFactory } from "@app/services/user/user-service";
import { injectIdentity } from "../plugins/auth/inject-identity";
import { registerV1Routes } from "./v1";
import { registerV2Routes } from "./v2";
import { registerV3Routes } from "./v3";
import { injectIdentity } from "../plugins/auth/inject-identity";
export const registerRoutes = async (
server: FastifyZodProvider,
{ db, smtp }: { db: Knex; smtp: TSmtpService }
{ db, smtp: smtpService }: { db: Knex; smtp: TSmtpService }
) => {
// db layers
const userDal = userDalFactory(db);
const authDal = authDalFactory(db);
const authTokenDal = tokenDalFactory(db);
const orgDal = orgDalFactory(db);
const incidentContactDal = incidentContactDalFactory(db);
const orgRoleDal = orgRoleDalFactory(db);
const serverCfgDal = serverCfgDalFactory(db);
const apiKeyDal = apiKeyDalFactory(db);
// ee db layer ops
const permissionDal = permissionDalFactory(db);
// ee services
const permissionService = permissionServiceFactory({ permissionDal });
// service layers
const tokenService = tokenServiceFactory({ tokenDal: authTokenDal });
const loginService = authLoginServiceFactory({ authDal, smtpService: smtp, tokenService });
const passwordService = authPaswordServiceFactory({ tokenService, smtpService: smtp, authDal });
const signupService = authSignupServiceFactory({ tokenService, smtpService: smtp, authDal });
const userService = userServiceFactory({ userDal });
const loginService = authLoginServiceFactory({ userDal, smtpService, tokenService });
const passwordService = authPaswordServiceFactory({
tokenService,
smtpService,
authDal,
userDal
});
const orgService = orgServiceFactory({
orgRoleDal,
permissionService,
orgDal,
incidentContactDal,
tokenService,
smtpService,
userDal
});
const signupService = authSignupServiceFactory({
tokenService,
smtpService,
authDal,
userDal,
orgDal,
orgService
});
const orgRoleService = orgRoleServiceFactory({ permissionService, orgRoleDal });
const serverCfgService = serverCfgServiceFactory({
userDal,
authService: loginService,
serverCfgDal
});
const apiKeyService = apiKeyServiceFactory({ apiKeyDal });
await serverCfgService.initServerCfg();
// inject all services
server.decorate("services", {
login: loginService,
password: passwordService,
signup: signupService
signup: signupService,
user: userService,
permission: permissionService,
org: orgService,
orgRole: orgRoleService,
serverCfg: serverCfgService,
apiKey: apiKeyService,
authToken: tokenService
} as FastifyZodProvider["services"]);
server.decorate("store", {
user: authDal
user: userDal
} as FastifyZodProvider["store"]);
await server.register(injectIdentity);
server.route({
url: "/status",
method: "GET",
schema: {
response: {
200: z.object({
date: z.date(),
message: z.literal("Ok"),
emailConfigured: z.boolean().optional(),
inviteOnlySignup: z.boolean().optional(),
redisConfigured: z.boolean().optional(),
secretScanningConfigured: z.boolean().optional()
})
}
},
handler: () => {
const appCfg = getConfig();
return {
date: new Date(),
message: "Ok" as const,
emailConfigured: appCfg.isSmtpConfigured,
inviteOnlySignup: false,
redisConfigured: false,
secretScanningConfigured: false
};
}
});
// register routes for v1
await server.register(registerV1Routes, { prefix: "/v1" });
await server.register(registerV2Routes, { prefix: "/v2" });
await server.register(registerV3Routes, { prefix: "/v3" });
await server.register(registerV1EERoutes, { prefix: "/ee/v1" });
};
+101
View File
@@ -0,0 +1,101 @@
import { z } from "zod";
import { ServerConfigSchema, UsersSchema } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { UnauthorizedError } from "@app/lib/errors";
import { verifySuperAdmin } from "@app/server/plugins/auth/superAdmin";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerAdminRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/config",
method: "GET",
schema: {
response: {
200: z.object({
config: ServerConfigSchema
})
}
},
handler: () => {
const config = server.services.serverCfg.getServerCfg();
return { config };
}
});
server.route({
url: "/config",
method: "PATCH",
schema: {
body: z.object({
allowSignUp: z.boolean().optional()
}),
response: {
200: z.object({
config: ServerConfigSchema
})
}
},
preHandler: (req) => {
verifyAuth([AuthMode.JWT, AuthMode.API_KEY])(req);
verifySuperAdmin(req);
},
handler: async (req) => {
const config = await server.services.serverCfg.updateServerCfg(req.body);
return { config };
}
});
server.route({
url: "/signup",
method: "POST",
schema: {
body: z.object({
email: z.string().email().trim(),
firstName: z.string().trim(),
lastName: z.string().trim().optional(),
protectedKey: z.string().trim(),
protectedKeyIV: z.string().trim(),
protectedKeyTag: z.string().trim(),
publicKey: z.string().trim(),
encryptedPrivateKey: z.string().trim(),
encryptedPrivateKeyIV: z.string().trim(),
encryptedPrivateKeyTag: z.string().trim(),
salt: z.string().trim(),
verifier: z.string().trim()
}),
response: {
200: z.object({
message: z.string(),
user: UsersSchema,
token: z.string()
})
}
},
handler: async (req, res) => {
const appCfg = getConfig();
const serverCfg = server.services.serverCfg.getServerCfg();
if (serverCfg.initialized)
throw new UnauthorizedError({ name: "Admin sign up", message: "Admin has been created" });
const { user, token } = await server.services.serverCfg.adminSignUp({
...req.body,
ip: req.realIp,
userAgent: req.headers["user-agent"] || ""
});
res.setCookie("jid", token.refresh, {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: appCfg.HTTPS_ENABLED
});
return {
message: "Successfully set up admin account",
user: user.user,
token: token.access
};
}
});
};
+88
View File
@@ -0,0 +1,88 @@
import jwt from "jsonwebtoken";
import { z } from "zod";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import {
AuthMode,
AuthModeRefreshJwtTokenPayload,
AuthTokenType
} from "@app/services/auth/auth-type";
export const registerAuthRoutes = async (server: FastifyZodProvider) => {
server.route({
url: "/logout",
method: "POST",
schema: {
response: {
200: z.object({
message: z.string()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req, res) => {
const appCfg = getConfig();
await server.services.login.logout(req.auth.userId, req.auth.tokenVersionId);
res.cookie("jid", "", {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: appCfg.HTTPS_ENABLED
});
return { message: "Successfully logged out" };
}
});
server.route({
url: "/token",
method: "POST",
schema: {
response: {
200: z.object({
token: z.string()
})
}
},
handler: async (req) => {
const refreshToken = req.cookies.jid;
const appCfg = getConfig();
if (!refreshToken)
throw new BadRequestError({
name: "Auth token route",
message: "Failed to find refresh token"
});
const decodedToken = jwt.verify(
refreshToken,
appCfg.JWT_AUTH_SECRET
) as AuthModeRefreshJwtTokenPayload;
if (decodedToken.authTokenType !== AuthTokenType.REFRESH_TOKEN)
throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" });
const tokenVersion = await server.services.authToken.getUserTokenSessionById(
decodedToken.tokenVersionId,
decodedToken.userId
);
if (!tokenVersion)
throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" });
if (decodedToken.refreshVersion !== tokenVersion.refreshVersion)
throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" });
const token = jwt.sign(
{
authTokenType: AuthTokenType.ACCESS_TOKEN,
userId: decodedToken.userId,
tokenVersionId: tokenVersion.id,
accessVersion: tokenVersion.accessVersion
},
appCfg.JWT_AUTH_SECRET,
{ expiresIn: appCfg.JWT_AUTH_LIFETIME }
);
return { token };
}
});
};
+12
View File
@@ -1,5 +1,17 @@
import { registerAdminRouter } from "./admin";
import { registerAuthRoutes } from "./auth";
import { registerInviteOrgRouter } from "./invite-org";
import { registerOrgRouter } from "./organization-router";
import { registerPasswordRouter } from "./password-router";
import { registerUserActionRouter } from "./user-action-router";
import { registerUserRouter } from "./user-router";
export const registerV1Routes = async (server: FastifyZodProvider) => {
await server.register(registerAuthRoutes, { prefix: "/auth" });
await server.register(registerPasswordRouter, { prefix: "/password" });
await server.register(registerOrgRouter, { prefix: "/organization" });
await server.register(registerAdminRouter, { prefix: "/admin" });
await server.register(registerUserRouter, { prefix: "/user" });
await server.register(registerInviteOrgRouter, { prefix: "/invite-org" });
await server.register(registerUserActionRouter, { prefix: "/user-action" });
};
@@ -0,0 +1,70 @@
import { z } from "zod";
import { UsersSchema } from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/signup",
method: "POST",
schema: {
body: z.object({
inviteeEmail: z.string().trim().email(),
organizationId: z.string().trim()
}),
response: {
200: z.object({
message: z.string(),
completeInviteLink: z.string().optional()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const completeInviteLink = await server.services.org.inviteUserToOrganization({
orgId: req.body.organizationId,
userId: req.auth.userId,
inviteeEmail: req.body.inviteeEmail
});
return {
completeInviteLink,
message: `Send an invite link to ${req.body.inviteeEmail}`
};
}
});
server.route({
url: "/verify",
method: "POST",
schema: {
body: z.object({
email: z.string().trim().email(),
organizationId: z.string().trim(),
code: z.string().trim()
}),
response: {
200: z.object({
message: z.string(),
token: z.string().optional(),
user: UsersSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { user, token } = await server.services.org.verifyUserToOrg({
orgId: req.body.organizationId,
code: req.body.code,
email: req.body.email
});
return {
message: "Successfully verified email",
user,
token
};
}
});
};
@@ -0,0 +1,183 @@
import { z } from "zod";
import {
IncidentContactsSchema,
OrganizationsSchema,
OrgMembershipsSchema,
UserEncryptionKeysSchema,
UsersSchema
} from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/",
schema: {
response: {
200: z.object({
organizations: OrganizationsSchema.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const organizations = await server.services.org.findAllOrganizationOfUser(req.auth.userId);
return { organizations };
}
});
server.route({
method: "GET",
url: "/:organizationId",
schema: {
params: z.object({
organizationId: z.string().trim()
}),
response: {
200: z.object({
organization: OrganizationsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const organization = await server.services.org.findOrganizationById(
req.auth.userId,
req.params.organizationId
);
return { organization };
}
});
server.route({
method: "GET",
url: "/:organizationId/users",
schema: {
params: z.object({
organizationId: z.string().trim()
}),
response: {
200: z.object({
users: OrgMembershipsSchema.merge(
z.object({
user: UsersSchema.pick({
email: true,
firstName: true,
lastName: true,
id: true
}).merge(UserEncryptionKeysSchema.pick({ publicKey: true }))
})
)
.omit({ createdAt: true, updatedAt: true })
.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const users = await server.services.org.findAllOrgMembers(
req.auth.userId,
req.params.organizationId
);
return { users };
}
});
// TODO(akhilmhdh-pg): missing my-workspace list
server.route({
method: "PATCH",
url: "/:organizationId/name",
schema: {
params: z.object({ organizationId: z.string().trim() }),
body: z.object({ name: z.string().trim() }),
response: {
200: z.object({
message: z.string(),
organization: OrganizationsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const organization = await server.services.org.updateOrgName(
req.auth.userId,
req.params.organizationId,
req.body.name
);
return {
message: "Successfully changed organization name",
organization
};
}
});
server.route({
method: "GET",
url: "/:organizationId/incidentContactOrg",
schema: {
params: z.object({ organizationId: z.string().trim() }),
response: {
200: z.object({
incidentContactsOrg: IncidentContactsSchema.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const incidentContactsOrg = await req.server.services.org.findIncidentContacts(
req.auth.userId,
req.params.organizationId
);
return { incidentContactsOrg };
}
});
server.route({
method: "POST",
url: "/:organizationId/incidentContactOrg",
schema: {
params: z.object({ organizationId: z.string().trim() }),
body: z.object({ email: z.string().email().trim() }),
response: {
200: z.object({
incidentContactsOrg: IncidentContactsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const incidentContactsOrg = await req.server.services.org.createIncidentContact(
req.auth.userId,
req.params.organizationId,
req.body.email
);
return { incidentContactsOrg };
}
});
server.route({
method: "DELETE",
url: "/:organizationId/incidentContactOrg/:incidentContactId",
schema: {
// TODO(akhilmhdh-pg): change accept id instead of email
params: z.object({ organizationId: z.string().trim(), incidentContactId: z.string().trim() }),
response: {
200: z.object({
incidentContactsOrg: IncidentContactsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const incidentContactsOrg = await req.server.services.org.deleteIncidentContact(
req.auth.userId,
req.params.organizationId,
req.params.incidentContactId
);
return { incidentContactsOrg };
}
});
};
@@ -0,0 +1,54 @@
import { z } from "zod";
import { UserActionsSchema } from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerUserActionRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/",
method: "POST",
schema: {
body: z.object({
action: z.string().trim()
}),
response: {
200: z.object({
message: z.string(),
userAction: UserActionsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const userAction = await server.services.user.createUserAction(
req.auth.userId,
req.body.action
);
return { userAction, message: "Successfully recorded user action" };
}
});
server.route({
url: "/",
method: "GET",
schema: {
querystring: z.object({
action: z.string().trim()
}),
response: {
200: z.object({
userAction: UserActionsSchema.optional().nullable()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const userAction = await server.services.user.getUserAction(
req.auth.userId,
req.query.action
);
return { userAction };
}
});
};
@@ -0,0 +1,24 @@
import { z } from "zod";
import { UsersSchema } from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/",
schema: {
response: {
200: z.object({
user: UsersSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const user = await server.services.user.getMe(req.auth.userId);
return { user };
}
});
};
+2
View File
@@ -1,5 +1,7 @@
import { registerMfaRouter } from "./mfa-router";
import { registerUserRouter } from "./user-router";
export const registerV2Routes = async (server: FastifyZodProvider) => {
await server.register(registerMfaRouter, { prefix: "/auth" });
await server.register(registerUserRouter, { prefix: "/users" });
};
@@ -25,7 +25,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
if (decodedToken.authTokenType !== AuthTokenType.MFA_TOKEN)
throw new Error("Unauthorized access");
const user = await server.store.user.getUserById(decodedToken.userId);
const user = await server.store.user.findById(decodedToken.userId);
if (!user) throw new Error("User not found");
req.mfa = { userId: user.id, user };
});
@@ -0,0 +1,140 @@
import { z } from "zod";
import {
OrganizationsSchema,
OrgMembershipsSchema,
UserEncryptionKeysSchema,
UsersSchema
} from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:organizationId/memberships",
schema: {
params: z.object({
organizationId: z.string().trim()
}),
response: {
200: z.object({
users: OrgMembershipsSchema.merge(
z.object({
user: UsersSchema.pick({
email: true,
firstName: true,
lastName: true,
id: true
}).merge(UserEncryptionKeysSchema.pick({ publicKey: true }))
})
)
.omit({ createdAt: true, updatedAt: true })
.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const users = await server.services.org.findAllOrgMembers(
req.auth.userId,
req.params.organizationId
);
return { users };
}
});
server.route({
method: "PATCH",
url: "/:organizationId/memberships/:membershipId",
schema: {
params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }),
body: z.object({
role: z.string().trim()
}),
response: {
200: z.object({
membership: OrgMembershipsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const membership = await server.services.org.updateOrgMembership({
userId: req.auth.userId,
role: req.body.role,
orgId: req.params.organizationId,
membershipId: req.params.membershipId
});
return { membership };
}
});
server.route({
method: "DELETE",
url: "/:organizationId/memberships/:membershipId",
schema: {
params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }),
response: {
200: z.object({
membership: OrgMembershipsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const membership = await server.services.org.deleteOrgMembership({
userId: req.auth.userId,
orgId: req.params.organizationId,
membershipId: req.params.membershipId
});
return { membership };
}
});
server.route({
method: "POST",
url: "/",
schema: {
body: z.object({
name: z.string().trim()
}),
response: {
200: z.object({
organization: OrganizationsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const organization = await server.services.org.createOrganization(
req.auth.userId,
req.body.name
);
return { organization };
}
});
server.route({
method: "DELETE",
url: "/:organizationId",
schema: {
params: z.object({
organizationId: z.string().trim()
}),
response: {
200: z.object({
organization: OrganizationsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const organization = await server.services.org.deleteOrganizationById(
req.auth.userId,
req.params.organizationId
);
return { organization };
}
});
};
@@ -0,0 +1,225 @@
import { z } from "zod";
import { AuthTokenSessionsSchema, OrganizationsSchema, UsersSchema } from "@app/db/schemas";
import { ApiKeysSchema } from "@app/db/schemas/api-keys";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMethod, AuthMode } from "@app/services/auth/auth-type";
export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/me/mfa",
method: "PATCH",
schema: {
body: z.object({
isMfaEnabled: z.boolean()
}),
response: {
200: z.object({
user: UsersSchema
})
}
},
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const user = await server.services.user.toggleUserMfa(req.auth.userId, req.body.isMfaEnabled);
return { user };
}
});
server.route({
url: "/me/name",
method: "PATCH",
schema: {
body: z.object({
firstName: z.string().trim(),
lastName: z.string().trim()
}),
response: {
200: z.object({
user: UsersSchema
})
}
},
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const user = await server.services.user.updateUserName(
req.auth.userId,
req.body.firstName,
req.body.lastName
);
return { user };
}
});
server.route({
url: "/me/auth-methods",
method: "PUT",
schema: {
body: z.object({
authMethods: z.nativeEnum(AuthMethod).array().min(1)
}),
response: {
200: z.object({
user: UsersSchema
})
}
},
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const user = await server.services.user.updateAuthMethods(
req.auth.userId,
req.body.authMethods
);
return { user };
}
});
server.route({
method: "GET",
url: "/me/organizations",
schema: {
response: {
200: z.object({
organizations: OrganizationsSchema.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const organizations = await server.services.org.findAllOrganizationOfUser(req.auth.userId);
return { organizations };
}
});
server.route({
method: "GET",
url: "/me/api-keys",
schema: {
response: {
200: ApiKeysSchema.omit({ secretHash: true }).array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const apiKeys = await server.services.apiKey.getMyApiKeys(req.auth.userId);
return apiKeys;
}
});
server.route({
method: "POST",
url: "/me/api-keys",
schema: {
body: z.object({
name: z.string().trim(),
expiresIn: z.number()
}),
response: {
200: z.object({
apiKey: z.string(),
apiKeyData: ApiKeysSchema.omit({ secretHash: true })
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const apiKeys = await server.services.apiKey.createApiKey(
req.auth.userId,
req.body.name,
req.body.expiresIn
);
return apiKeys;
}
});
server.route({
method: "DELETE",
url: "/me/api-keys/:apiKeyDataId",
schema: {
params: z.object({
apiKeyDataId: z.string().trim()
}),
response: {
200: z.object({
apiKeyData: ApiKeysSchema.omit({ secretHash: true })
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const apiKeyData = await server.services.apiKey.deleteApiKey(
req.auth.userId,
req.params.apiKeyDataId
);
return { apiKeyData };
}
});
server.route({
method: "GET",
url: "/me/sessions",
schema: {
response: {
200: AuthTokenSessionsSchema.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const sessions = await server.services.authToken.getTokenSessionByUser(req.auth.userId);
return sessions;
}
});
server.route({
method: "DELETE",
url: "/me/sessions",
schema: {
response: {
200: z.object({
message: z.string()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
await server.services.authToken.revokeAllMySessions(req.auth.userId);
return {
message: "Successfully revoked all sessions"
};
}
});
server.route({
method: "GET",
url: "/me",
schema: {
response: {
200: z.object({
user: UsersSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const user = await server.services.user.getMe(req.auth.userId);
return { user };
}
});
server.route({
method: "DELETE",
url: "/me",
schema: {
response: {
200: z.object({
user: UsersSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const user = await server.services.user.deleteMe(req.auth.userId);
return { user };
}
});
};
+2
View File
@@ -1,7 +1,9 @@
import { registerLoginRouter } from "./login-router";
import { registerSignupRouter } from "./signup-router";
import { registerUserRouter } from "./user-router";
export const registerV3Routes = async (server: FastifyZodProvider) => {
await server.register(registerSignupRouter, { prefix: "/signup" });
await server.register(registerLoginRouter, { prefix: "/auth" });
await server.register(registerUserRouter, { prefix: "/users" });
};
@@ -100,4 +100,54 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
return { message: "Successfully set up account", user, token: accessToken };
}
});
server.route({
url: "/complete-account/invite",
method: "POST",
schema: {
body: z.object({
email: z.string().email().trim(),
firstName: z.string().trim(),
lastName: z.string().trim().optional(),
protectedKey: z.string().trim(),
protectedKeyIV: z.string().trim(),
protectedKeyTag: z.string().trim(),
publicKey: z.string().trim(),
encryptedPrivateKey: z.string().trim(),
encryptedPrivateKeyIV: z.string().trim(),
encryptedPrivateKeyTag: z.string().trim(),
salt: z.string().trim(),
verifier: z.string().trim()
}),
response: {
200: z.object({
message: z.string(),
user: UsersSchema,
token: z.string()
})
}
},
handler: async (req, res) => {
const userAgent = req.headers["user-agent"];
if (!userAgent) throw new Error("user agent header is required");
const appCfg = getConfig();
const { user, accessToken, refreshToken } =
await server.services.signup.completeAccountInvite({
...req.body,
ip: req.realIp,
userAgent
});
res.setCookie("jid", refreshToken, {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: appCfg.HTTPS_ENABLED
});
// TODO(akhilmhdh-pg): add telemetry service
return { message: "Successfully set up account", user, token: accessToken };
}
});
};
@@ -0,0 +1,24 @@
import { z } from "zod";
import { ApiKeysSchema } from "@app/db/schemas/api-keys";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/me/api-keys",
schema: {
response: {
200: z.object({
apiKeyData: ApiKeysSchema.omit({ secretHash: true }).array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const apiKeyData = await server.services.apiKey.getMyApiKeys(req.auth.userId);
return { apiKeyData };
}
});
};