All checks were successful
backend-action / build-image (push) Successful in 1m9s
85 lines
2.0 KiB
TypeScript
85 lines
2.0 KiB
TypeScript
import { initTRPC } from "@trpc/server";
|
|
import type { CreateHTTPContextOptions } from "@trpc/server/adapters/standalone";
|
|
import { db } from "./db";
|
|
import * as jwt from "jsonwebtoken";
|
|
import { Config } from "./config";
|
|
import { z } from "zod";
|
|
const t = initTRPC.context<Context>().create();
|
|
|
|
export const router = t.router;
|
|
export const publicProcedure = t.procedure;
|
|
export const protectedProcedure = t.procedure.use(async (opts) => {
|
|
const { ctx } = opts;
|
|
if (ctx.user === undefined) {
|
|
throw new Error("Unauthorized");
|
|
} else {
|
|
return opts.next({
|
|
ctx: {
|
|
...ctx,
|
|
user: ctx.user,
|
|
},
|
|
});
|
|
}
|
|
});
|
|
export const verifiedPhone = t.procedure.use(async (opts) => {
|
|
const { ctx } = opts;
|
|
if (ctx.phone === undefined) {
|
|
throw new Error("Unauthorized");
|
|
} else {
|
|
return opts.next({
|
|
ctx: {
|
|
phone: ctx.phone,
|
|
},
|
|
});
|
|
}
|
|
});
|
|
|
|
type Context = Awaited<ReturnType<typeof createContext>>;
|
|
|
|
export const createContext = async (opts: CreateHTTPContextOptions) => {
|
|
const authorizationHeader = opts.req.headers.authorization || "";
|
|
|
|
const bearerToken = authorizationHeader.split(" ")[1];
|
|
const phone = await verifyToken(bearerToken);
|
|
if (phone !== null) {
|
|
const user = await db.query.user.findFirst({
|
|
where: (user, { eq }) => eq(user.phone, phone),
|
|
});
|
|
return {
|
|
phone,
|
|
user: user,
|
|
};
|
|
} else {
|
|
return {
|
|
phone: undefined,
|
|
user: undefined,
|
|
};
|
|
}
|
|
};
|
|
|
|
async function verifyToken(token: string): Promise<string | null> {
|
|
try {
|
|
const rs = await new Promise((resolve, reject) => {
|
|
jwt.verify(token, Config.jwt_secret, (err, decoded) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
resolve(decoded);
|
|
}
|
|
});
|
|
});
|
|
const data = z
|
|
.object({
|
|
phone: z.string(),
|
|
})
|
|
.safeParse(rs);
|
|
if (data.success) {
|
|
return data.data.phone;
|
|
} else {
|
|
return null;
|
|
}
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|