refactor #26

Merged
vivy-agent merged 5 commits from refactor into main 2026-03-11 10:12:24 +07:00
10 changed files with 346 additions and 28 deletions
Showing only changes of commit da74f5e3e1 - Show all commits

View File

@ -10,25 +10,15 @@ export interface ClientInfoHeader {
ip: string; ip: string;
} }
export const getUserHeaderInformation = ( export const getUserHeaderInformation = (ctx: Context): UserHeaderInformation => {
ctx: Context,
): UserHeaderInformation => {
const clientInfoHeader = const clientInfoHeader =
(JSON.parse( (JSON.parse(ctx.request.headers.get("x-client-info") as string) as ClientInfoHeader) ?? ("unknown" as string);
ctx.request.headers.get("x-client-info") as string,
) as ClientInfoHeader) ?? ("unknown" as string);
const userHeaderInformation = { const userHeaderInformation = {
ip: clientInfoHeader.ip ?? "unknown", ip: clientInfoHeader.ip ?? "unknown",
deviceType: clientInfoHeader.deviceType ?? "unknown", deviceType: clientInfoHeader.deviceType ?? "unknown",
deviceOS: deviceOS: (clientInfoHeader.os ?? "unknown") + " " + (clientInfoHeader.osVersion ?? "unknown"),
(clientInfoHeader.os ?? "unknown") + browser: (clientInfoHeader.browser ?? "unknown") + " " + (clientInfoHeader.browserVersion ?? "unknown"),
" " +
(clientInfoHeader.osVersion ?? "unknown"),
browser:
(clientInfoHeader.browser ?? "unknown") +
" " +
(clientInfoHeader.browserVersion ?? "unknown"),
}; };
return userHeaderInformation; return userHeaderInformation;

View File

@ -5,7 +5,7 @@ import { googleCallbackService } from "../services/http/googleCallback.service";
import { getUserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation"; import { getUserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation";
export const googleCallbackController = async ( export const googleCallbackController = async (
ctx: Context & { query: { code: string; state: string; callbackURI: string } } ctx: Context & { query: { code: string; state: string; callbackURI: string } },
) => { ) => {
try { try {
const userHeaderInfo = getUserHeaderInformation(ctx); const userHeaderInfo = getUserHeaderInformation(ctx);

View File

@ -1,14 +1,16 @@
import { Context } from "elysia"; import { Context, Static } from "elysia";
import { mainErrorHandler } from "../../../helpers/error/handler"; import { mainErrorHandler } from "../../../helpers/error/handler";
import { googleRequestService } from "../services/http/googleRequest.service"; import { googleRequestService } from "../services/http/googleRequest.service";
import { returnReadResponse } from "../../../helpers/callback/httpResponse"; import { returnReadResponse } from "../../../helpers/callback/httpResponse";
import { googleRequestSchema } from "../schemas/googleRequest.schema";
export const googleRequestController = async ( export const googleRequestController = async (ctx: {
ctx: Context & { query: { callback?: string } } set: Context["set"];
) => { query: Static<typeof googleRequestSchema.query>;
}) => {
try { try {
const loginUrl = await googleRequestService(ctx.query.callback); const loginUrl = await googleRequestService(ctx.query.callback);
return returnReadResponse(ctx.set, 200, "Google login url created!", { return returnReadResponse(ctx.set, 200, "Google login URL created successfully.", {
endpointUrl: loginUrl, endpointUrl: loginUrl,
}); });
} catch (error) { } catch (error) {

View File

@ -9,13 +9,16 @@ import { tokenValidationController } from "./controllers/tokenValidation.control
import { logoutController } from "./controllers/logout.controller"; import { logoutController } from "./controllers/logout.controller";
import { tokenValidationSchema } from "./schemas/tokenValidation.schema"; import { tokenValidationSchema } from "./schemas/tokenValidation.schema";
import { getOauthProvidersSchema } from "./schemas/getOauthProviders.schema"; import { getOauthProvidersSchema } from "./schemas/getOauthProviders.schema";
import { getCallbackProviderUrlSchema } from "./schemas/getCallbackProviderUrl.schema";
import { googleRequestSchema } from "./schemas/googleRequest.schema";
import { googleCallbackSchema } from "./schemas/googleCallback.schema";
export const authModule = new Elysia({ prefix: "/auth", tags: ["Authentication"] }) export const authModule = new Elysia({ prefix: "/auth", tags: ["Authentication"] })
.post("/token/validate", tokenValidationController, tokenValidationSchema) .post("/token/validate", tokenValidationController, tokenValidationSchema)
.get("/providers", getOauthProvidersController, getOauthProvidersSchema) .get("/providers", getOauthProvidersController, getOauthProvidersSchema)
.get("/providers/:name/callback", getCallbackProviderUrlController) .get("/providers/:name/callback", getCallbackProviderUrlController, getCallbackProviderUrlSchema)
.get("/google", googleRequestController, googleRequestSchema)
.get("/google/callback", googleCallbackController, googleCallbackSchema)
.get("/github", githubRequestController) .get("/github", githubRequestController)
.get("/github/callback", githubCallbackController) .get("/github/callback", githubCallbackController)
.get("/google", googleRequestController)
.get("/google/callback", googleCallbackController)
.post("/logout", logoutController); .post("/logout", logoutController);

View File

@ -0,0 +1,45 @@
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
export const getCallbackProviderUrlSchema = {
detail: {
summary: "Get the callback URL of oauth provider",
description:
"After users have successfully completed the authentication process on the OAuth provider page, they will be redirected to the callback page on the frontend. This endpoint aims to obtain the actual endpoint for each OAuth response handler.",
responses: {
200: {
description: "The callback URL on the provider has been found.",
content: {
"application/json": {
schema: {
type: "object",
properties: {
success: {
type: "boolean",
default: true,
},
status: {
type: "number",
default: 200,
},
message: {
type: "string",
default: "The callback URL on the provider has been found.",
},
data: {
type: "object",
properties: {
callback_url: {
type: "string",
description: "The callback URL on the provider.",
example: "auth/google/callback",
},
},
},
},
},
},
},
},
},
},
} satisfies AppRouteSchema;

View File

@ -0,0 +1,58 @@
import { t } from "elysia";
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
export const googleCallbackSchema = {
headers: t.Object({
"x-client-info": t.String({
examples: [
'{"os":"Windows","osVersion":"10","browser":"Chrome","browserVersion":"89.0.4389.82","deviceType":"Desktop","ip":"192.168.1.1"}',
],
}),
}),
query: t.Object({
code: t.String({ examples: ["4/0AY0e-xxxxxxxxx"] }),
state: t.String({ examples: ["random_state_string"] }),
callbackURI: t.String({ examples: ["https://example.com/auth/google/callback"] }),
}),
detail: {
summary: "Google OAuth callback endpoint",
description:
"Handles the callback from Google OAuth and processes the authentication response. This endpoint also processes the account provisioning if the user is logging in for the first time.",
responses: {
200: {
description: "Authentication successful",
content: {
"application/json": {
schema: {
type: "object",
properties: {
success: {
type: "boolean",
example: true,
},
status: {
type: "number",
example: 200,
},
message: {
type: "string",
example: "Authentication successful",
},
data: {
type: "object",
properties: {
authToken: {
type: "string",
description: "JWT token for authenticated user",
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
},
},
},
},
},
},
},
},
},
},
} satisfies AppRouteSchema;

View File

@ -0,0 +1,54 @@
import { t } from "elysia";
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
export const googleRequestSchema = {
query: t.Object({
callback: t.Optional(
t.String({
description: "The callback URL to redirect after Google authentication. It should be URL-encoded if provided.",
}),
),
}),
detail: {
summary: "Initiate Google OAuth flow",
description:
"This endpoint initiates the Google OAuth flow by redirecting the user to Google's authentication page.",
responses: {
200: {
description: "Google login URL created successfully.",
content: {
"application/json": {
schema: {
type: "object",
properties: {
success: {
type: "boolean",
default: true,
},
status: {
type: "number",
default: 200,
},
message: {
type: "string",
default: "Google login URL created successfully.",
},
data: {
type: "object",
properties: {
endpointUrl: {
type: "string",
description: "The URL to redirect the user for Google authentication.",
example:
"https://accounts.google.com/o/oauth2/v2/auth?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code&scope=email%20profile",
},
},
},
},
},
},
},
},
},
},
} satisfies AppRouteSchema;