From ef5e626c9dcc8ebe221ab6140fbf2078fa42eba2 Mon Sep 17 00:00:00 2001 From: Wanjohi Date: Mon, 27 Oct 2025 01:23:14 +0300 Subject: [PATCH] fix: Fix the auth API middleware --- packages/core/src/actor.ts | 23 ++++++------- packages/core/src/examples.ts | 1 - packages/core/src/steam/index.ts | 46 +++++++++++++++++++++---- packages/function/src/api/utils/auth.ts | 32 +++++++++-------- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/packages/core/src/actor.ts b/packages/core/src/actor.ts index 56aec8bd..e4ff5ead 100644 --- a/packages/core/src/actor.ts +++ b/packages/core/src/actor.ts @@ -3,27 +3,26 @@ import { Context } from "./context.js"; import { ErrorCodes, VisibleError } from "./error.js"; export namespace Actor { - export interface Member { - type: "member"; + export interface User { + type: "user"; properties: { + userID: string; email: string; - teamID: string; - memberID: string; }; } - export interface Team { - type: "team"; + export interface Steam { + type: "steam"; properties: { - teamID: string; - email: string; + userID: string; + steamID: string; }; } export interface System { type: "system"; properties: { - teamID: string; + userID: string; }; } @@ -40,13 +39,13 @@ export namespace Actor { properties: {}; } - export type Info = Team | Member | Public | Token | System; + export type Info = Steam | User | Public | Token | System; export const ctx = Context.create(); - export function teamID() { + export function userID() { const actor = ctx.use(); - if ("teamID" in actor.properties) return actor.properties.teamID; + if ("userID" in actor.properties) return actor.properties.userID; throw new VisibleError( "authentication", ErrorCodes.Authentication.UNAUTHORIZED, diff --git a/packages/core/src/examples.ts b/packages/core/src/examples.ts index 4ef21c82..7557793a 100644 --- a/packages/core/src/examples.ts +++ b/packages/core/src/examples.ts @@ -22,7 +22,6 @@ export namespace Examples { id: "74839300282033", // Steam ID ownerID: User.id, name: "JD The 65th", - username: "jdoe", realName: "John Doe", memberSince: new Date("2010-01-26T21:00:00.000Z"), avatarHash: "3a5e805fd4c1e04e26a97af0b9c6fab2dee91a19", diff --git a/packages/core/src/steam/index.ts b/packages/core/src/steam/index.ts index 94170d5f..c2994555 100644 --- a/packages/core/src/steam/index.ts +++ b/packages/core/src/steam/index.ts @@ -1,6 +1,10 @@ import { z } from "zod/v4"; import { Examples } from "../examples.js"; -import { Limitations } from "./steam.sql.js"; +import { Limitations, steamTable } from "./steam.sql.js"; +import { fn } from "../utils/fn.js"; +import { Actor } from "../actor.js"; +import { Database } from "../drizzle/index.js"; +import { eq, isNull, and } from "drizzle-orm"; export namespace Steam { export const Info = z @@ -18,10 +22,6 @@ export namespace Steam { description: "The display name of the Steam account", example: Examples.SteamAccount.name, }), - username: z.string().meta({ - description: "The username of the Steam account", - example: Examples.SteamAccount.username, - }), realName: z.string().nullable().meta({ description: "The real name associated with the Steam account", example: Examples.SteamAccount.realName, @@ -38,7 +38,7 @@ export namespace Steam { description: "Account limitations and restrictions", example: Examples.SteamAccount.limitations, }), - profileUrl: z.string().meta({ + profileUrl: z.string().nullable().meta({ description: "The Steam community profile URL or identifier", example: Examples.SteamAccount.profileUrl, }), @@ -54,4 +54,38 @@ export namespace Steam { }); export type Info = z.infer; + + export const fromID = fn(Info.shape.id, async (id) => { + const userID = Actor.userID(); + + return Database.transaction((tx) => + tx + .select() + .from(steamTable) + .where( + and( + eq(steamTable.id, id), + eq(steamTable.ownerID, userID), + isNull(steamTable.timeDeleted), + ), + ) + .then((rows) => rows.map(serialize).at(0)), + ); + }); + + export function serialize( + input: typeof steamTable.$inferSelect, + ): z.infer { + return { + id: input.id, + name: input.name, + ownerID: input.ownerID, + realName: input.realName, + profileUrl: input.profileUrl, + memberSince: input.memberSince, + avatarHash: input.avatarHash, + limitations: input.limitations, + lastSyncedAt: input.lastSyncedAt, + }; + } } diff --git a/packages/function/src/api/utils/auth.ts b/packages/function/src/api/utils/auth.ts index 727dc2f3..af7bf304 100644 --- a/packages/function/src/api/utils/auth.ts +++ b/packages/function/src/api/utils/auth.ts @@ -2,13 +2,13 @@ import { subjects } from "@/subjects"; import { MiddlewareHandler } from "hono"; import { Actor } from "@nestri/core/actor"; import { Api } from "@nestri/core/api/index"; -import { Member } from "@nestri/core/member/index"; +import { Steam } from "@nestri/core/steam/index"; import { createClient } from "@openauthjs/openauth/client"; import { VisibleError, ErrorCodes } from "@nestri/core/error"; const client = createClient({ clientID: "api", - issuer: process.env.AUTH_URL, + issuer: process.env.AUTH_URL || "http://localhost:3000", subjects, }); @@ -52,15 +52,14 @@ export const auth: MiddlewareHandler = async (c, next) => { ErrorCodes.Authentication.INVALID_TOKEN, "Invalid bearer token", ); - if (result.subject.type === "team") { - const memberID = - c.req.header("x-nestri-member") || c.req.query("memberID"); - if (!memberID) { + if (result.subject.type === "user") { + const steamID = c.req.header("x-nestri-steam") || c.req.query("steamID"); + if (!steamID) { return Actor.provide( - "team", + "user", { email: result.subject.properties.email, - teamID: result.subject.properties.teamID, + userID: result.subject.properties.userID, }, next, ); @@ -69,17 +68,20 @@ export const auth: MiddlewareHandler = async (c, next) => { return Actor.provide( "system", { - teamID: result.subject.properties.teamID, + userID: result.subject.properties.userID, }, async () => { - const member = await Member.fromID(email); - if (!member || member.timeDeleted) { - c.status(401); - return c.text("Unauthorized: User not found"); + const steamAcc = await Steam.fromID(steamID); + if (!steamAcc) { + throw new VisibleError( + "authentication", + ErrorCodes.Authentication.INVALID_TOKEN, + "Invalid bearer token", + ); } return Actor.provide( - "member", - { memberID: member.id, teamID: member.workspaceID }, + "steam", + { steamID: steamAcc.id, userID: steamAcc.ownerID }, next, ); },