mirror of
https://github.com/Chewbaccalakis/rfid-database.git
synced 2026-09-10 00:11:56 -07:00
Implement RFID tag dump PWA with REST API, auth, and CI (#1)
Add Next.js app with SQLite/Drizzle storage for sites and LF/HF tag dumps, multi-user Auth.js (credentials + optional OIDC), personal API tokens in Settings, versioned /api/v1 for UI and future CLI use, MCT/Proxmark/JSON import-export, PWA offline shell, Vitest tests, and GitHub Actions CI. Co-authored-by: Cursor Agent <[email protected]>
This commit is contained in:
co-authored by
Cursor Agent
parent
5029945cc2
commit
8500d2f673
@@ -0,0 +1,85 @@
|
||||
import { z } from "zod";
|
||||
import { FREQUENCIES, PROTOCOLS } from "@/lib/rfid/protocols";
|
||||
|
||||
export const mifareClassicDumpSchema = z.object({
|
||||
size: z.enum(["1K", "4K"]),
|
||||
sectors: z.array(
|
||||
z.object({
|
||||
index: z.number().int().min(0),
|
||||
blocks: z.array(z.string().regex(/^[0-9A-Fa-f]+$/)).min(1),
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
export const ntagDumpSchema = z.object({
|
||||
pages: z.array(
|
||||
z.object({
|
||||
index: z.number().int().min(0),
|
||||
data: z.string().regex(/^[0-9A-Fa-f]+$/),
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
export const lfDumpSchema = z.object({
|
||||
uidBytes: z.string().regex(/^[0-9A-Fa-f]+$/),
|
||||
format: z.string().min(1),
|
||||
});
|
||||
|
||||
export const dumpDataSchema = z.union([
|
||||
mifareClassicDumpSchema,
|
||||
ntagDumpSchema,
|
||||
lfDumpSchema,
|
||||
z.record(z.string(), z.unknown()),
|
||||
]);
|
||||
|
||||
export const keysSchema = z
|
||||
.object({
|
||||
A: z.array(z.string()).optional(),
|
||||
B: z.array(z.string()).optional(),
|
||||
})
|
||||
.passthrough()
|
||||
.nullable()
|
||||
.optional();
|
||||
|
||||
export const siteCreateSchema = z.object({
|
||||
name: z.string().min(1).max(200),
|
||||
code: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(32)
|
||||
.regex(/^[A-Za-z0-9_-]+$/, "Code must be alphanumeric"),
|
||||
notes: z.string().max(5000).nullable().optional(),
|
||||
});
|
||||
|
||||
export const siteUpdateSchema = siteCreateSchema.partial();
|
||||
|
||||
export const tagCreateSchema = z.object({
|
||||
siteId: z.string().uuid(),
|
||||
label: z.string().min(1).max(200),
|
||||
frequency: z.enum(FREQUENCIES),
|
||||
protocol: z.enum(PROTOCOLS),
|
||||
uid: z.string().min(1),
|
||||
dumpData: dumpDataSchema,
|
||||
keys: keysSchema,
|
||||
notes: z.string().max(5000).nullable().optional(),
|
||||
lastWrittenAt: z.string().datetime().nullable().optional(),
|
||||
});
|
||||
|
||||
export const tagUpdateSchema = tagCreateSchema.partial().omit({ siteId: true }).extend({
|
||||
siteId: z.string().uuid().optional(),
|
||||
});
|
||||
|
||||
export const tagUpsertSchema = tagCreateSchema;
|
||||
|
||||
export const tokenCreateSchema = z.object({
|
||||
name: z.string().min(1).max(100),
|
||||
expiresAt: z.string().datetime().nullable().optional(),
|
||||
});
|
||||
|
||||
export const exportFormatSchema = z.enum(["json", "proxmark", "mct", "hex"]);
|
||||
|
||||
export type MifareClassicDump = z.infer<typeof mifareClassicDumpSchema>;
|
||||
export type NtagDump = z.infer<typeof ntagDumpSchema>;
|
||||
export type LfDump = z.infer<typeof lfDumpSchema>;
|
||||
export type DumpData = z.infer<typeof dumpDataSchema>;
|
||||
export type TagKeys = z.infer<typeof keysSchema>;
|
||||
Reference in New Issue
Block a user