@open-core/identity 1.0.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +54 -658
  2. package/dist/contracts.d.ts +93 -0
  3. package/dist/contracts.js +21 -0
  4. package/dist/entities/account.entity.js +1 -2
  5. package/dist/entities/role.entity.js +1 -2
  6. package/dist/events/identity.events.js +1 -2
  7. package/dist/index.d.ts +86 -67
  8. package/dist/index.js +110 -99
  9. package/dist/providers/auth/api-auth.provider.d.ts +52 -0
  10. package/dist/providers/auth/api-auth.provider.js +82 -0
  11. package/dist/providers/auth/credentials-auth.provider.d.ts +63 -0
  12. package/dist/providers/auth/credentials-auth.provider.js +149 -0
  13. package/dist/providers/auth/local-auth.provider.d.ts +82 -0
  14. package/dist/providers/auth/local-auth.provider.js +151 -0
  15. package/dist/providers/identity-auth.provider.d.ts +0 -0
  16. package/dist/providers/identity-auth.provider.js +1 -0
  17. package/dist/providers/principal/api-principal.provider.d.ts +50 -0
  18. package/dist/providers/principal/api-principal.provider.js +84 -0
  19. package/dist/providers/principal/local-principal.provider.d.ts +77 -0
  20. package/dist/providers/principal/local-principal.provider.js +164 -0
  21. package/dist/repositories/account.repository.d.ts +4 -4
  22. package/dist/repositories/account.repository.js +2 -6
  23. package/dist/repositories/role.repository.d.ts +4 -4
  24. package/dist/repositories/role.repository.js +2 -6
  25. package/dist/services/account.service.d.ts +52 -57
  26. package/dist/services/account.service.js +80 -166
  27. package/dist/services/auth/api-auth.provider.js +7 -10
  28. package/dist/services/auth/credentials-auth.provider.js +8 -44
  29. package/dist/services/auth/local-auth.provider.js +7 -10
  30. package/dist/services/cache/memory-cache.service.js +4 -7
  31. package/dist/services/identity-auth.provider.js +7 -10
  32. package/dist/services/identity-principal.provider.js +12 -15
  33. package/dist/services/principal/api-principal.provider.js +9 -12
  34. package/dist/services/principal/local-principal.provider.js +12 -15
  35. package/dist/services/role.service.d.ts +33 -54
  36. package/dist/services/role.service.js +51 -109
  37. package/dist/setup.js +25 -28
  38. package/dist/tokens.d.ts +7 -0
  39. package/dist/tokens.js +7 -0
  40. package/dist/types/auth.types.js +1 -2
  41. package/dist/types/index.js +1 -2
  42. package/dist/types.d.ts +170 -0
  43. package/dist/types.js +1 -0
  44. package/package.json +13 -8
  45. package/migrations/001_accounts_table.sql +0 -16
  46. package/migrations/002_roles_table.sql +0 -21
  47. package/migrations/003_alter_accounts_add_role.sql +0 -24
  48. package/migrations/004_rename_uuid_to_linked_id.sql +0 -12
  49. package/migrations/005_add_password_hash.sql +0 -7
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
2
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
3
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -8,138 +7,81 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
7
  var __metadata = (this && this.__metadata) || function (k, v) {
9
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
9
  };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.RoleService = void 0;
13
- const tsyringe_1 = require("tsyringe");
14
- const role_repository_1 = require("../repositories/role.repository");
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { injectable, inject } from "tsyringe";
14
+ import { IDENTITY_OPTIONS } from "../tokens";
15
+ import { RoleStore } from "../contracts";
15
16
  /**
16
- * Service for managing roles and their permissions.
17
- * Handles CRUD operations and permission management for roles.
17
+ * High-level service for managing security roles and their associated permissions.
18
+ *
19
+ * Provides a programmer-friendly API for role administration, including creation,
20
+ * updates, and permission retrieval. This service interacts with the configured
21
+ * {@link RoleStore}.
22
+ *
23
+ * @public
24
+ * @injectable
18
25
  */
19
26
  let RoleService = class RoleService {
20
- constructor(repo) {
21
- this.repo = repo;
22
- }
23
- /**
24
- * Find a role by its ID.
25
- *
26
- * @param id - Role ID
27
- * @returns The role or null if not found
28
- */
29
- async findById(id) {
30
- return this.repo.findById(id);
31
- }
32
27
  /**
33
- * Find a role by its internal name.
28
+ * Initializes a new instance of the RoleService.
34
29
  *
35
- * @param name - Role name (e.g., 'admin', 'user')
36
- * @returns The role or null if not found
30
+ * @param store - Persistence layer for role definitions.
31
+ * @param options - Identity system configuration options.
37
32
  */
38
- async findByName(name) {
39
- return this.repo.findByName(name);
33
+ constructor(store, options) {
34
+ this.store = store;
35
+ this.options = options;
40
36
  }
41
37
  /**
42
- * Get all roles.
38
+ * Persists a new security role definition.
43
39
  *
44
- * @returns Array of all roles
40
+ * @param role - The complete role definition to create.
41
+ * @returns A promise that resolves when the role is saved.
45
42
  */
46
- async getAll() {
47
- const result = await this.repo.findMany();
48
- return result.data;
43
+ async create(role) {
44
+ await this.store.save(role);
49
45
  }
50
46
  /**
51
- * Get the default role for new accounts.
47
+ * Updates an existing role's rank or permissions.
52
48
  *
53
- * @returns The default role or null if none is configured
49
+ * @param name - The unique technical name of the role to update.
50
+ * @param data - Partial object containing the fields to modify.
51
+ * @returns A promise that resolves when the update is complete.
54
52
  */
55
- async getDefaultRole() {
56
- return this.repo.getDefaultRole();
57
- }
58
- /**
59
- * Create a new role.
60
- *
61
- * @param input - Role creation data
62
- * @returns The created role
63
- */
64
- async create(input) {
65
- const now = new Date();
66
- const role = {
67
- id: 0, // Will be set by DB
68
- name: input.name,
69
- displayName: input.displayName,
70
- rank: input.rank,
71
- permissions: input.permissions ?? [],
72
- isDefault: input.isDefault ?? false,
73
- createdAt: now,
74
- };
75
- return this.repo.save(role);
76
- }
77
- /**
78
- * Update an existing role.
79
- *
80
- * @param id - Role ID
81
- * @param input - Update data
82
- * @returns The updated role or null if not found
83
- */
84
- async update(id, input) {
85
- const existing = await this.repo.findById(id);
53
+ async update(name, data) {
54
+ const existing = await this.store.findByName(name);
86
55
  if (!existing)
87
- return null;
88
- const updated = {
56
+ return;
57
+ await this.store.save({
89
58
  ...existing,
90
- ...(input.displayName !== undefined && {
91
- displayName: input.displayName,
92
- }),
93
- ...(input.rank !== undefined && { rank: input.rank }),
94
- ...(input.permissions !== undefined && {
95
- permissions: input.permissions,
96
- }),
97
- };
98
- if (input.isDefault !== undefined) {
99
- await this.repo.setDefault(id, input.isDefault);
100
- updated.isDefault = input.isDefault;
101
- }
102
- return this.repo.save(updated);
103
- }
104
- /**
105
- * Delete a role.
106
- *
107
- * @param id - Role ID
108
- * @returns true if deleted, false if not found
109
- */
110
- async delete(id) {
111
- return this.repo.delete(id);
59
+ ...data,
60
+ });
112
61
  }
113
62
  /**
114
- * Add a permission to a role.
63
+ * Permanently removes a role definition from the system.
115
64
  *
116
- * @param roleId - Role ID
117
- * @param permission - Permission string to add
65
+ * @param name - The technical name of the role to delete.
66
+ * @returns A promise that resolves when the role is deleted.
118
67
  */
119
- async addPermission(roleId, permission) {
120
- const role = await this.repo.findById(roleId);
121
- if (!role)
122
- return;
123
- const permissions = new Set(role.permissions);
124
- permissions.add(permission);
125
- await this.repo.updatePermissions(roleId, Array.from(permissions));
68
+ async delete(name) {
69
+ await this.store.delete(name);
126
70
  }
127
71
  /**
128
- * Remove a permission from a role.
72
+ * Retrieves the full list of permissions granted to a specific role.
129
73
  *
130
- * @param roleId - Role ID
131
- * @param permission - Permission string to remove
74
+ * @param name - The technical name of the role.
75
+ * @returns A promise resolving to an array of permission strings.
132
76
  */
133
- async removePermission(roleId, permission) {
134
- const role = await this.repo.findById(roleId);
135
- if (!role)
136
- return;
137
- const filtered = role.permissions.filter((p) => p !== permission);
138
- await this.repo.updatePermissions(roleId, filtered);
77
+ async getPermissions(name) {
78
+ const role = await this.store.findByName(name);
79
+ return role?.permissions || [];
139
80
  }
140
81
  };
141
- exports.RoleService = RoleService;
142
- exports.RoleService = RoleService = __decorate([
143
- (0, tsyringe_1.injectable)(),
144
- __metadata("design:paramtypes", [role_repository_1.RoleRepository])
82
+ RoleService = __decorate([
83
+ injectable(),
84
+ __param(1, inject(IDENTITY_OPTIONS)),
85
+ __metadata("design:paramtypes", [RoleStore, Object])
145
86
  ], RoleService);
87
+ export { RoleService };
package/dist/setup.js CHANGED
@@ -1,18 +1,15 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setupIdentity = setupIdentity;
4
- const account_repository_1 = require("./repositories/account.repository");
5
- const role_repository_1 = require("./repositories/role.repository");
6
- const account_service_1 = require("./services/account.service");
7
- const role_service_1 = require("./services/role.service");
8
- const memory_cache_service_1 = require("./services/cache/memory-cache.service");
9
- const local_auth_provider_1 = require("./services/auth/local-auth.provider");
10
- const credentials_auth_provider_1 = require("./services/auth/credentials-auth.provider");
11
- const api_auth_provider_1 = require("./services/auth/api-auth.provider");
12
- const local_principal_provider_1 = require("./services/principal/local-principal.provider");
13
- const api_principal_provider_1 = require("./services/principal/api-principal.provider");
14
- const identity_auth_provider_1 = require("./services/identity-auth.provider");
15
- const identity_principal_provider_1 = require("./services/identity-principal.provider");
1
+ import { AccountRepository } from "./repositories/account.repository";
2
+ import { RoleRepository } from "./repositories/role.repository";
3
+ import { AccountService } from "./services/account.service";
4
+ import { RoleService } from "./services/role.service";
5
+ import { MemoryCacheService } from "./services/cache/memory-cache.service";
6
+ import { LocalAuthProvider } from "./services/auth/local-auth.provider";
7
+ import { CredentialsAuthProvider } from "./services/auth/credentials-auth.provider";
8
+ import { ApiAuthProvider } from "./services/auth/api-auth.provider";
9
+ import { LocalPrincipalProvider } from "./services/principal/local-principal.provider";
10
+ import { ApiPrincipalProvider } from "./services/principal/api-principal.provider";
11
+ import { IdentityAuthProvider } from "./services/identity-auth.provider";
12
+ import { IdentityPrincipalProvider } from "./services/identity-principal.provider";
16
13
  /**
17
14
  * Register all Identity module singletons with the DI container.
18
15
  *
@@ -45,49 +42,49 @@ const identity_principal_provider_1 = require("./services/identity-principal.pro
45
42
  * });
46
43
  * ```
47
44
  */
48
- function setupIdentity(container, options = {}) {
45
+ export function setupIdentity(container, options = {}) {
49
46
  const { authProvider = "local", principalProvider = "local", useDatabase = authProvider !== "api" && principalProvider !== "api", } = options;
50
47
  // Always register cache service (needed for API providers)
51
- container.registerSingleton(memory_cache_service_1.MemoryCacheService);
48
+ container.registerSingleton(MemoryCacheService);
52
49
  // Register database-dependent services only if needed
53
50
  if (useDatabase) {
54
- container.registerSingleton(account_repository_1.AccountRepository);
55
- container.registerSingleton(role_repository_1.RoleRepository);
56
- container.registerSingleton(account_service_1.AccountService);
57
- container.registerSingleton(role_service_1.RoleService);
51
+ container.registerSingleton(AccountRepository);
52
+ container.registerSingleton(RoleRepository);
53
+ container.registerSingleton(AccountService);
54
+ container.registerSingleton(RoleService);
58
55
  }
59
56
  // Register Auth Provider based on strategy
60
57
  switch (authProvider) {
61
58
  case "credentials":
62
- container.registerSingleton("AuthProviderContract", credentials_auth_provider_1.CredentialsAuthProvider);
59
+ container.registerSingleton("AuthProviderContract", CredentialsAuthProvider);
63
60
  // Also register as IdentityAuthProvider for backward compatibility
64
61
  // Note: CredentialsAuthProvider is not compatible with IdentityAuthProvider interface
65
62
  // Users should use the new provider directly
66
63
  break;
67
64
  case "api":
68
- container.registerSingleton("AuthProviderContract", api_auth_provider_1.ApiAuthProvider);
65
+ container.registerSingleton("AuthProviderContract", ApiAuthProvider);
69
66
  // Note: ApiAuthProvider is not compatible with IdentityAuthProvider interface
70
67
  // Users should use the new provider directly
71
68
  break;
72
69
  case "local":
73
70
  default:
74
- container.registerSingleton("AuthProviderContract", local_auth_provider_1.LocalAuthProvider);
71
+ container.registerSingleton("AuthProviderContract", LocalAuthProvider);
75
72
  // Register LocalAuthProvider as the legacy IdentityAuthProvider for compatibility
76
- container.registerSingleton(identity_auth_provider_1.IdentityAuthProvider, local_auth_provider_1.LocalAuthProvider);
73
+ container.registerSingleton(IdentityAuthProvider, LocalAuthProvider);
77
74
  break;
78
75
  }
79
76
  // Register Principal Provider based on strategy
80
77
  switch (principalProvider) {
81
78
  case "api":
82
- container.registerSingleton("PrincipalProviderContract", api_principal_provider_1.ApiPrincipalProvider);
79
+ container.registerSingleton("PrincipalProviderContract", ApiPrincipalProvider);
83
80
  // Note: ApiPrincipalProvider is not compatible with IdentityPrincipalProvider interface
84
81
  // Users should use the new provider directly
85
82
  break;
86
83
  case "local":
87
84
  default:
88
- container.registerSingleton("PrincipalProviderContract", local_principal_provider_1.LocalPrincipalProvider);
85
+ container.registerSingleton("PrincipalProviderContract", LocalPrincipalProvider);
89
86
  // Register LocalPrincipalProvider as the legacy IdentityPrincipalProvider for compatibility
90
- container.registerSingleton(identity_principal_provider_1.IdentityPrincipalProvider, local_principal_provider_1.LocalPrincipalProvider);
87
+ container.registerSingleton(IdentityPrincipalProvider, LocalPrincipalProvider);
91
88
  break;
92
89
  }
93
90
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Injection Token for the Identity configuration options.
3
+ * Required because IdentityOptions is an interface and cannot be injected by type.
4
+ *
5
+ * @public
6
+ */
7
+ export declare const IDENTITY_OPTIONS = "IdentityOptions";
package/dist/tokens.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Injection Token for the Identity configuration options.
3
+ * Required because IdentityOptions is an interface and cannot be injected by type.
4
+ *
5
+ * @public
6
+ */
7
+ export const IDENTITY_OPTIONS = "IdentityOptions";
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Authentication strategy modes.
3
+ *
4
+ * - `local`: Automatic authentication based on FiveM connection identifiers (e.g., license, discord).
5
+ * Ideal for traditional FiveM servers where account creation should be transparent.
6
+ * - `credentials`: Manual authentication using username and password.
7
+ * Suitable for servers with an integrated registration system.
8
+ * - `api`: Delegation of authentication to an external HTTP API.
9
+ * Useful for servers integrated with a web dashboard or external auth service.
10
+ *
11
+ * @public
12
+ */
13
+ export type AuthMode = "local" | "credentials" | "api";
14
+ /**
15
+ * Authorization and principal resolution modes.
16
+ *
17
+ * - `roles`: Uses a static role hierarchy defined in the application code.
18
+ * Provides the best performance and version control for role definitions.
19
+ * - `db`: Fetches roles and permissions dynamically from a persistent store.
20
+ * - `api`: Fetches principal data from an external HTTP API on demand.
21
+ *
22
+ * @public
23
+ */
24
+ export type PrincipalMode = "roles" | "db" | "api";
25
+ /**
26
+ * Represents a security role within the identity system.
27
+ *
28
+ * Roles define base permissions and a rank hierarchy used by the framework's `@Guard` decorator.
29
+ *
30
+ * @public
31
+ */
32
+ export interface IdentityRole {
33
+ /**
34
+ * Technical identifier for the role (e.g., 'admin', 'moderator', 'user').
35
+ */
36
+ name: string;
37
+ /**
38
+ * Hierarchical weight.
39
+ *
40
+ * Used for rank-based authorization.
41
+ * Logic: UserRank >= RequiredRank.
42
+ */
43
+ rank: number;
44
+ /**
45
+ * List of permission strings granted to this role by default.
46
+ *
47
+ * Supports '*' wildcard for full framework access.
48
+ */
49
+ permissions: string[];
50
+ /**
51
+ * Human-readable label for UI display or chat prefix.
52
+ */
53
+ displayName?: string;
54
+ }
55
+ /**
56
+ * Global configuration options for the OpenCore Identity System.
57
+ *
58
+ * @public
59
+ */
60
+ export interface IdentityOptions {
61
+ /**
62
+ * Authentication configuration.
63
+ */
64
+ auth: {
65
+ /**
66
+ * The strategy to use for authenticating players.
67
+ */
68
+ mode: AuthMode;
69
+ /**
70
+ * Whether to automatically create a new account when a player connects
71
+ * with valid identifiers that are not yet registered.
72
+ *
73
+ * Only applicable when mode is 'local'.
74
+ * @defaultValue true
75
+ */
76
+ autoCreate?: boolean;
77
+ /**
78
+ * The primary FiveM identifier used to unique-link an account.
79
+ * @defaultValue 'license'
80
+ */
81
+ primaryIdentifier?: string;
82
+ };
83
+ /**
84
+ * Authorization and permissions configuration.
85
+ */
86
+ principal: {
87
+ /**
88
+ * The strategy to use for resolving roles and permissions.
89
+ */
90
+ mode: PrincipalMode;
91
+ /**
92
+ * Static role definitions.
93
+ *
94
+ * Required when mode is 'roles'.
95
+ */
96
+ roles?: Record<string, IdentityRole>;
97
+ /**
98
+ * The name of the role assigned to newly created accounts.
99
+ * @defaultValue 'user'
100
+ */
101
+ defaultRole?: string;
102
+ /**
103
+ * Time-to-live in milliseconds for cached principal data.
104
+ *
105
+ * Since principal resolution is a high-frequency operation, caching is
106
+ * critical for performance.
107
+ * @defaultValue 300000 (5 minutes)
108
+ */
109
+ cacheTtl?: number;
110
+ };
111
+ }
112
+ /**
113
+ * Represents a persistent identity account.
114
+ *
115
+ * This object links a FiveM player to their persistent roles, permissions,
116
+ * and operational status (e.g., bans).
117
+ *
118
+ * @public
119
+ */
120
+ export interface IdentityAccount {
121
+ /**
122
+ * Internal unique database/store ID.
123
+ */
124
+ id: string;
125
+ /**
126
+ * External stable ID used by the framework (linkedID).
127
+ *
128
+ * Usually a UUID or an external system ID.
129
+ */
130
+ linkedId: string;
131
+ /**
132
+ * Primary connection identifier (e.g., 'license:123...').
133
+ */
134
+ identifier: string;
135
+ /**
136
+ * Current technical role name assigned to this account.
137
+ */
138
+ roleName: string;
139
+ /**
140
+ * Optional technical username for credentials-based authentication.
141
+ */
142
+ username?: string | null;
143
+ /**
144
+ * Hashed password for credentials-based authentication.
145
+ *
146
+ * @internal
147
+ */
148
+ passwordHash?: string | null;
149
+ /**
150
+ * List of specific permission overrides for this account.
151
+ *
152
+ * - `+perm`: Explicitly grant a permission.
153
+ * - `-perm`: Explicitly revoke a permission (even if granted by role).
154
+ */
155
+ customPermissions: string[];
156
+ /**
157
+ * Whether the account is currently prohibited from connecting.
158
+ */
159
+ isBanned: boolean;
160
+ /**
161
+ * The reason provided for the current ban.
162
+ */
163
+ banReason?: string;
164
+ /**
165
+ * Timestamp when the ban expires.
166
+ *
167
+ * If null and isBanned is true, the ban is permanent.
168
+ */
169
+ banExpiresAt?: Date | null;
170
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "@open-core/identity",
3
- "version": "1.0.0",
4
- "description": "Flexible identity and authentication system for OpenCore Framework",
3
+ "version": "1.2.1",
4
+ "description": "Enterprise-grade identity, authentication, and authorization plugin for OpenCore Framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js",
11
+ "require": "./dist/index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
7
15
  "scripts": {
8
16
  "build": "tsc -p tsconfig.json",
9
17
  "clean": "rimraf dist",
@@ -30,7 +38,7 @@
30
38
  },
31
39
  "packageManager": "pnpm@10.13.1",
32
40
  "dependencies": {
33
- "@open-core/framework": "^1.0.1-beta.1",
41
+ "@open-core/framework": "^0.2.4",
34
42
  "bcrypt": "^6.0.0",
35
43
  "reflect-metadata": "^0.2.2",
36
44
  "tsyringe": "^4.10.0",
@@ -39,15 +47,12 @@
39
47
  },
40
48
  "devDependencies": {
41
49
  "@types/bcrypt": "^6.0.0",
42
- "@types/node": "^22.7.5",
43
- "@typescript-eslint/eslint-plugin": "^8.48.1",
44
- "@typescript-eslint/parser": "^8.48.1",
50
+ "@types/node": "^22.19.1",
45
51
  "eslint": "^9.39.1",
46
52
  "eslint-config-prettier": "^10.1.8",
47
- "eslint-plugin-import": "^2.32.0",
48
53
  "eslint-plugin-prettier": "^5.5.4",
49
54
  "prettier": "3.7.1",
50
- "rimraf": "^6.0.1",
55
+ "rimraf": "^6.1.2",
51
56
  "typescript": "^5.9.3"
52
57
  },
53
58
  "files": [
@@ -1,16 +0,0 @@
1
- CREATE TABLE IF NOT EXISTS accounts (
2
- id INT AUTO_INCREMENT PRIMARY KEY,
3
- linked_id VARCHAR(255) UNIQUE NULL,
4
- external_source VARCHAR(32) NULL,
5
- license VARCHAR(64) UNIQUE,
6
- discord VARCHAR(32) UNIQUE,
7
- steam VARCHAR(32) UNIQUE,
8
- username VARCHAR(64),
9
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
10
- last_login_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
11
- banned BOOLEAN DEFAULT FALSE,
12
- ban_reason TEXT,
13
- ban_expires TIMESTAMP NULL,
14
- permissions JSON DEFAULT '[]'
15
- );
16
-
@@ -1,21 +0,0 @@
1
- -- Migration 002: Create roles table
2
- -- This table stores security roles/ranks with hierarchical permissions.
3
-
4
- CREATE TABLE IF NOT EXISTS roles (
5
- id INT AUTO_INCREMENT PRIMARY KEY,
6
- name VARCHAR(64) NOT NULL UNIQUE,
7
- display_name VARCHAR(128) NOT NULL,
8
- rank INT NOT NULL DEFAULT 0,
9
- permissions JSON DEFAULT '[]',
10
- is_default BOOLEAN DEFAULT FALSE,
11
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
12
-
13
- INDEX idx_name (name),
14
- INDEX idx_is_default (is_default)
15
- );
16
-
17
- -- Insert default role for new accounts
18
- INSERT INTO roles (name, display_name, rank, permissions, is_default)
19
- VALUES ('user', 'Player', 0, '[]', TRUE)
20
- ON DUPLICATE KEY UPDATE name=name;
21
-
@@ -1,24 +0,0 @@
1
- -- Migration 003: Alter accounts table to use role-based permissions
2
- -- IMPORTANT: Run this AFTER creating roles and inserting at least a default role.
3
-
4
- -- Add role_id foreign key column
5
- ALTER TABLE accounts
6
- ADD COLUMN role_id INT NULL AFTER username;
7
-
8
- -- Add custom_permissions column for per-account overrides
9
- ALTER TABLE accounts
10
- ADD COLUMN custom_permissions JSON DEFAULT '[]' AFTER role_id;
11
-
12
- -- Drop old flat permissions column
13
- ALTER TABLE accounts
14
- DROP COLUMN IF EXISTS permissions;
15
-
16
- -- Add foreign key constraint to roles
17
- ALTER TABLE accounts
18
- ADD CONSTRAINT fk_accounts_role
19
- FOREIGN KEY (role_id) REFERENCES roles(id)
20
- ON DELETE SET NULL;
21
-
22
- -- Add index for faster role lookups
23
- CREATE INDEX idx_role_id ON accounts(role_id);
24
-
@@ -1,12 +0,0 @@
1
- -- Migration to rename uuid column to linked_id and add external_source
2
- -- This migration is for existing installations that already have the accounts table
3
-
4
- -- Rename uuid column to linked_id and increase length to support various ID formats
5
- ALTER TABLE accounts CHANGE COLUMN uuid linked_id VARCHAR(255) UNIQUE NULL;
6
-
7
- -- Add external_source column to track account origin
8
- ALTER TABLE accounts ADD COLUMN external_source VARCHAR(32) NULL AFTER linked_id;
9
-
10
- -- Update existing records to mark them as 'local' source
11
- UPDATE accounts SET external_source = 'local' WHERE external_source IS NULL;
12
-
@@ -1,7 +0,0 @@
1
- -- Add password_hash column for credentials-based authentication
2
- -- This is optional and only needed if using CredentialsAuthProvider
3
-
4
- ALTER TABLE accounts ADD COLUMN password_hash VARCHAR(255) NULL AFTER username;
5
-
6
- -- Note: For existing systems, passwords can be set via AccountService.setPassword()
7
-