get coutry using maxmind and clear stale device codes

This commit is contained in:
miloschwartz
2025-12-08 21:12:19 -05:00
parent ede51bebb5
commit 048ce850a8
2 changed files with 21 additions and 13 deletions

View File

@@ -13,10 +13,12 @@ import { maxmindLookup } from "@server/db/maxmind";
import { encodeHexLowerCase } from "@oslojs/encoding"; import { encodeHexLowerCase } from "@oslojs/encoding";
import { sha256 } from "@oslojs/crypto/sha2"; import { sha256 } from "@oslojs/crypto/sha2";
const bodySchema = z.object({ const bodySchema = z
deviceName: z.string().optional(), .object({
applicationName: z.string().min(1, "Application name is required") deviceName: z.string().optional(),
}).strict(); applicationName: z.string().min(1, "Application name is required")
})
.strict();
export type StartDeviceWebAuthBody = z.infer<typeof bodySchema>; export type StartDeviceWebAuthBody = z.infer<typeof bodySchema>;
@@ -34,14 +36,12 @@ function generateDeviceCode(): string {
// Helper function to hash device code before storing in database // Helper function to hash device code before storing in database
function hashDeviceCode(code: string): string { function hashDeviceCode(code: string): string {
return encodeHexLowerCase( return encodeHexLowerCase(sha256(new TextEncoder().encode(code)));
sha256(new TextEncoder().encode(code))
);
} }
// Helper function to extract IP from request // Helper function to extract IP from request
function extractIpFromRequest(req: Request): string | undefined { function extractIpFromRequest(req: Request): string | undefined {
const ip = req.ip || req.socket.remoteAddress; const ip = req.ip;
if (!ip) { if (!ip) {
return undefined; return undefined;
} }
@@ -75,10 +75,10 @@ async function getCityFromIp(ip: string): Promise<string | undefined> {
return undefined; return undefined;
} }
// MaxMind CountryResponse doesn't include city by default if (result.country) {
// If city data is available, it would be in result.city?.names?.en return result.country.names?.en || result.country.iso_code;
// But since we're using CountryResponse type, we'll just return undefined }
// The user said "don't do this if not easy", so we'll skip city for now
return undefined; return undefined;
} catch (error) { } catch (error) {
logger.debug("Failed to get city from IP", error); logger.debug("Failed to get city from IP", error);

View File

@@ -1,5 +1,5 @@
import { build } from "@server/build"; import { build } from "@server/build";
import { db, sessionTransferToken } from "@server/db"; import { db, deviceWebAuthCodes, sessionTransferToken } from "@server/db";
import { import {
emailVerificationCodes, emailVerificationCodes,
newtSessions, newtSessions,
@@ -89,4 +89,12 @@ export async function clearStaleData() {
logger.warn("Error clearing expired sessionTransferToken:", e); logger.warn("Error clearing expired sessionTransferToken:", e);
} }
} }
try {
await db
.delete(deviceWebAuthCodes)
.where(lt(deviceWebAuthCodes.expiresAt, new Date().getTime()));
} catch (e) {
logger.warn("Error clearing expired deviceWebAuthCodes:", e);
}
} }