feat: age verification with an ID document (Didit), and closed registration
Age: a Didit provider behind the vendor-neutral age interface. A person verifies once (ID document, passive liveness, face match) and all their linked IMVU accounts count as adult. Webhooks are checked against Didit's signatures; only "over 18" is kept. A later answer replaces an earlier one (an approval taken back is revoked). Checks are limited: one unfinished check per person, 3 in 30 days, none once verified, and a monthly cap (DIDIT_MONTHLY_LIMIT, default 30: Didit's free plan is $10 of credit a month and a check costs $0.30). The Account page gets an Age Verification card. Registration: open or closed, an admin's setting in the console (default from REGISTRATION). Closed: new accounts can only sign in until a moderator approves them (or declines, deleting the account); the website shows them a waiting page and the API treats them as signed out. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
86ebe976ba
commit
c75a4c9afc
28 files changed
+3260
-89
No files matched your search
@@ -0,0 +1,7 @@
|
||||
CREATE TABLE "hub_setting" (
|
||||
"key" text PRIMARY KEY NOT NULL,
|
||||
"value" text NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "user" ADD COLUMN "approved" boolean DEFAULT true NOT NULL;
|
||||
File diff suppressed because it is too large.
Load diff
@@ -64,6 +64,13 @@
|
||||
"when": 1793372872749,
|
||||
"tag": "0008_product_deletion",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"version": "7",
|
||||
"when": 1793707706030,
|
||||
"tag": "0009_registration",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -43,6 +43,8 @@ export const user = pgTable(
|
||||
banExpires: timestamp("ban_expires", { withTimezone: true }),
|
||||
// How many IMVU accounts the person may link; moderators raise it on request.
|
||||
linkCap: integer("link_cap").notNull().default(10),
|
||||
// False while a new account waits for a moderator's approval (registration closed); it can only sign in.
|
||||
approved: boolean("approved").notNull().default(true),
|
||||
},
|
||||
(t) => [uniqueIndex("user_username_lower").on(sql`lower(${t.username})`)],
|
||||
);
|
||||
@@ -473,3 +475,10 @@ export const roomDecoration = pgTable(
|
||||
},
|
||||
(t) => [index("room_decoration_owner").on(t.ownerImvuId)],
|
||||
);
|
||||
|
||||
// The hub's settings that admins change from the console (e.g. registration: "open" or "closed").
|
||||
export const hubSetting = pgTable("hub_setting", {
|
||||
key: text("key").primaryKey(),
|
||||
value: text("value").notNull(),
|
||||
updatedAt: updatedAt(),
|
||||
});
|
||||
Reference in new issue
Block a user