feat: windows support

This commit is contained in:
zhom
2026-02-15 11:48:59 +04:00
parent dd5afac951
commit 63453331ff
46 changed files with 2445 additions and 328 deletions
+48 -7
View File
@@ -2,14 +2,26 @@ import {
type CanActivate,
type ExecutionContext,
Injectable,
Logger,
UnauthorizedException,
} from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import type { Request } from "express";
import * as jwt from "jsonwebtoken";
import type { UserContext } from "./user-context.interface.js";
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private configService: ConfigService) {}
private readonly logger = new Logger(AuthGuard.name);
private jwtPublicKey: string | null = null;
constructor(private configService: ConfigService) {
const publicKey = this.configService.get<string>("SYNC_JWT_PUBLIC_KEY");
if (publicKey) {
this.jwtPublicKey = publicKey.replace(/\\n/g, "\n");
this.logger.log("JWT public key configured — cloud auth enabled");
}
}
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest<Request>();
@@ -22,16 +34,45 @@ export class AuthGuard implements CanActivate {
}
const token = authHeader.substring(7);
// Try SYNC_TOKEN first (self-hosted mode)
const expectedToken = this.configService.get<string>("SYNC_TOKEN");
if (!expectedToken) {
throw new UnauthorizedException("Sync token not configured on server");
if (expectedToken && token === expectedToken) {
(request as any).user = {
mode: "self-hosted",
prefix: "",
teamPrefix: null,
profileLimit: 0,
} satisfies UserContext;
return true;
}
if (token !== expectedToken) {
throw new UnauthorizedException("Invalid sync token");
// Try JWT verification (cloud mode)
if (this.jwtPublicKey) {
try {
const decoded = jwt.verify(token, this.jwtPublicKey, {
algorithms: ["RS256"],
}) as jwt.JwtPayload;
(request as any).user = {
mode: "cloud",
prefix: decoded.prefix || `users/${decoded.sub}/`,
teamPrefix: decoded.teamPrefix || null,
profileLimit: decoded.profileLimit || 0,
} satisfies UserContext;
return true;
} catch {
// JWT verification failed — fall through to error
}
}
return true;
// If SYNC_TOKEN is configured but didn't match, or JWT failed
if (!expectedToken && !this.jwtPublicKey) {
throw new UnauthorizedException(
"No auth method configured on server (set SYNC_TOKEN or SYNC_JWT_PUBLIC_KEY)",
);
}
throw new UnauthorizedException("Invalid sync token or JWT");
}
}
@@ -0,0 +1,6 @@
export interface UserContext {
mode: "self-hosted" | "cloud";
prefix: string; // '' for self-hosted, 'users/{id}/' for cloud
teamPrefix: string | null; // 'teams/{id}/' or null
profileLimit: number; // 0 for unlimited (self-hosted)
}