diff --git a/src/backend/clients/database/SqliteDatabaseClient.ts b/src/backend/clients/database/SqliteDatabaseClient.ts
index 03604a117..5604e05af 100644
--- a/src/backend/clients/database/SqliteDatabaseClient.ts
+++ b/src/backend/clients/database/SqliteDatabaseClient.ts
@@ -85,6 +85,7 @@ const AVAILABLE_MIGRATIONS: [number, string[]][] = [
[50, ['0054_sessions_workers.sql']],
[50, ['0055_username_nocase_unique.sql']],
[51, ['0056_sessions_kind_worker.sql']],
+ [52, ['0057_add_user_reputation.sql']],
];
export class SqliteDatabaseClient extends AbstractDatabaseClient {
diff --git a/src/backend/clients/database/migrations/sqlite/0057_add_user_reputation.sql b/src/backend/clients/database/migrations/sqlite/0057_add_user_reputation.sql
new file mode 100644
index 000000000..bb663ef7d
--- /dev/null
+++ b/src/backend/clients/database/migrations/sqlite/0057_add_user_reputation.sql
@@ -0,0 +1,21 @@
+-- Copyright (C) 2024-present Puter Technologies Inc.
+--
+-- This file is part of Puter.
+--
+-- Puter is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero General Public License as published
+-- by the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see .
+
+-- Abuse v2 reputation score (0–100+) recorded at signup. Mirrors the
+-- `reputation smallint DEFAULT 100` column already present in the mysql and
+-- postgres baseline migrations.
+ALTER TABLE `user` ADD COLUMN `reputation` SMALLINT DEFAULT 100;
diff --git a/src/backend/clients/event/types.ts b/src/backend/clients/event/types.ts
index a274ef831..3c6e4b0e2 100644
--- a/src/backend/clients/event/types.ts
+++ b/src/backend/clients/event/types.ts
@@ -130,7 +130,7 @@ export type EventMap = {
req?: unknown;
data?: unknown;
abuse?: unknown;
- custom?: unknown;
+ trail?: Array;
[key: string]: unknown;
};
'puter.signup.success': {
diff --git a/src/backend/controllers/auth/AuthController.ts b/src/backend/controllers/auth/AuthController.ts
index b5afe366a..b3f253928 100644
--- a/src/backend/controllers/auth/AuthController.ts
+++ b/src/backend/controllers/auth/AuthController.ts
@@ -557,6 +557,9 @@ export class AuthController extends PuterController {
message: null,
code: null,
user_agent: req?.headers?.['user-agent'] ?? null,
+ // Populated by the abuse extension's v2 harness; persisted to the
+ // user row below so the signup-time reputation is referable later.
+ reputation: null as number | null,
};
try {
await this.clients.event?.emitAndWait(
@@ -622,6 +625,11 @@ export class AuthController extends PuterController {
// stays hardcoded here.
requires_email_confirmation: 1,
last_activity_ts: signupSqlTs,
+ // Record the v2 reputation from this claim (skip if unset so we
+ // don't clobber an existing score with a placeholder).
+ ...(validateEvent.reputation != null
+ ? { reputation: validateEvent.reputation }
+ : {}),
});
// Move from temp group to regular user group
@@ -678,6 +686,7 @@ export class AuthController extends PuterController {
signup_server: (this.config as { serverId?: string }).serverId,
referrer: req.body.referrer ?? null,
last_activity_ts: signupSqlTs,
+ reputation: validateEvent.reputation,
} as never);
// Add to default group
diff --git a/src/backend/stores/user/UserStore.ts b/src/backend/stores/user/UserStore.ts
index efee906f6..70f93fef7 100644
--- a/src/backend/stores/user/UserStore.ts
+++ b/src/backend/stores/user/UserStore.ts
@@ -43,6 +43,8 @@ export interface UserRow {
requires_email_confirmation?: boolean;
/** Metadata JSON blob; decoded on read when the DB returns it as a string. */
metadata?: Record;
+ /** Abuse v2 reputation score recorded at signup (DB default 100). */
+ reputation?: number;
password?: string;
[k: string]: unknown;
}
@@ -324,6 +326,7 @@ export class UserStore extends PuterStore {
signup_server?: string | null;
referrer?: string | null;
last_activity_ts?: string | null;
+ reputation?: number | null;
}): Promise {
assertLatin1Writable(fields as Record);
const result = await this.clients.db.write(
@@ -344,8 +347,9 @@ export class UserStore extends PuterStore {
signup_origin,
signup_server,
referrer,
- last_activity_ts)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)${this.clients.db.returningIdClause()}`,
+ last_activity_ts,
+ reputation)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)${this.clients.db.returningIdClause()}`,
[
fields.username,
fields.email,
@@ -368,6 +372,8 @@ export class UserStore extends PuterStore {
fields.signup_server ?? null,
fields.referrer ?? null,
fields.last_activity_ts ?? null,
+ // Default matches the DB column default + v2's STARTING_REPUTATION.
+ fields.reputation ?? 100,
],
);
@@ -577,6 +583,8 @@ export class UserStore extends PuterStore {
requires_email_confirmation: asBool(
rest.requires_email_confirmation,
),
+ reputation:
+ rest.reputation == null ? undefined : Number(rest.reputation),
metadata,
};
}