Skip to content

Conversation

@jmgasper
Copy link
Contributor

Skip Vanilla if no user exists, and additional validation to ensure the new handle meets requirements.

exports.Prisma.Security_userScalarFieldEnum = {
login_id: 'login_id',
user_id: 'user_id',
password: 'password',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ security]
Storing passwords as plain text in the password field is a security risk. Consider using a secure hashing algorithm (e.g., bcrypt) to store password hashes instead.

},
"inlineSchema": "generator identityClient {\n provider = \"prisma-client-js\"\n output = \"./generated/identity-client\"\n}\n\ndatasource identitydb {\n provider = \"postgresql\"\n url = env(\"IDENTITY_DB_URL\")\n schemas = [\"identity\"]\n}\n\nmodel user {\n user_id Decimal @id(map: \"u175_45\") @default(dbgenerated(\"nextval('sequence_user_seq'::regclass)\")) @identitydb.Decimal(10, 0)\n handle String @identitydb.VarChar(50)\n handle_lower String? @identitydb.VarChar(50)\n modify_date DateTime? @default(now()) @identitydb.Timestamp(6)\n status String @identitydb.VarChar(3)\n\n @@index([handle])\n @@index([handle_lower], map: \"user_lower_handle_idx\")\n @@index([status, handle_lower])\n @@map(\"user\")\n @@schema(\"identity\")\n}\n\nmodel email {\n email_id Decimal @id(map: \"u110_23\") @default(dbgenerated(\"nextval('sequence_email_seq'::regclass)\")) @identitydb.Decimal(10, 0)\n user_id Decimal? @identitydb.Decimal(10, 0)\n address String? @identitydb.VarChar(100)\n modify_date DateTime? @default(now()) @identitydb.Timestamp(6)\n\n @@index([user_id], map: \"email_user_id_idx\")\n @@index([address])\n @@map(\"email\")\n @@schema(\"identity\")\n}\n",
"inlineSchemaHash": "c5a596f0918d1322e0688539e5f1dd09423833ad2a87dca3d89817938caeaaf8",
"inlineSchema": "generator identityClient {\n provider = \"prisma-client-js\"\n output = \"./generated/identity-client\"\n}\n\ndatasource identitydb {\n provider = \"postgresql\"\n url = env(\"IDENTITY_DB_URL\")\n schemas = [\"identity\"]\n}\n\nmodel user {\n user_id Decimal @id(map: \"u175_45\") @default(dbgenerated(\"nextval('sequence_user_seq'::regclass)\")) @identitydb.Decimal(10, 0)\n handle String @identitydb.VarChar(50)\n handle_lower String? @identitydb.VarChar(50)\n modify_date DateTime? @default(now()) @identitydb.Timestamp(6)\n status String @identitydb.VarChar(3)\n\n @@index([handle])\n @@index([handle_lower], map: \"user_lower_handle_idx\")\n @@index([status, handle_lower])\n @@map(\"user\")\n @@schema(\"identity\")\n}\n\nmodel email {\n email_id Decimal @id(map: \"u110_23\") @default(dbgenerated(\"nextval('sequence_email_seq'::regclass)\")) @identitydb.Decimal(10, 0)\n user_id Decimal? @identitydb.Decimal(10, 0)\n address String? @identitydb.VarChar(100)\n modify_date DateTime? @default(now()) @identitydb.Timestamp(6)\n\n @@index([user_id], map: \"email_user_id_idx\")\n @@index([address])\n @@map(\"email\")\n @@schema(\"identity\")\n}\n\nmodel security_user {\n login_id Decimal @id(map: \"pk_security_user\") @identitydb.Decimal(12, 0)\n user_id String @unique(map: \"security_user_i2\") @identitydb.VarChar(50)\n password String @identitydb.VarChar(300)\n create_user_id Decimal? @identitydb.Decimal(12, 0)\n modify_date DateTime? @identitydb.Timestamp(6)\n\n @@map(\"security_user\")\n @@schema(\"identity\")\n}\n",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
The user_id field in the security_user model is marked as String and unique. Ensure that this aligns with the database schema and that the uniqueness constraint is enforced at the database level.

exports.Prisma.Security_userScalarFieldEnum = {
login_id: 'login_id',
user_id: 'user_id',
password: 'password',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ security]
Storing passwords as plain text or using weak encryption is a security risk. Ensure that the password field is securely hashed and salted before storage.

}

config.runtimeDataModel = JSON.parse("{\"models\":{\"user\":{\"dbName\":\"user\",\"schema\":\"identity\",\"fields\":[{\"name\":\"user_id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Decimal\",\"nativeType\":[\"Decimal\",[\"10\",\"0\"]],\"default\":{\"name\":\"dbgenerated\",\"args\":[\"nextval('sequence_user_seq'::regclass)\"]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"handle\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":[\"VarChar\",[\"50\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"handle_lower\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":[\"VarChar\",[\"50\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"modify_date\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":[\"Timestamp\",[\"6\"]],\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"status\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":[\"VarChar\",[\"3\"]],\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"email\":{\"dbName\":\"email\",\"schema\":\"identity\",\"fields\":[{\"name\":\"email_id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Decimal\",\"nativeType\":[\"Decimal\",[\"10\",\"0\"]],\"default\":{\"name\":\"dbgenerated\",\"args\":[\"nextval('sequence_email_seq'::regclass)\"]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"user_id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Decimal\",\"nativeType\":[\"Decimal\",[\"10\",\"0\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"address\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":[\"VarChar\",[\"100\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"modify_date\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":[\"Timestamp\",[\"6\"]],\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false}},\"enums\":{},\"types\":{}}")
config.runtimeDataModel = JSON.parse("{\"models\":{\"user\":{\"dbName\":\"user\",\"schema\":\"identity\",\"fields\":[{\"name\":\"user_id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Decimal\",\"nativeType\":[\"Decimal\",[\"10\",\"0\"]],\"default\":{\"name\":\"dbgenerated\",\"args\":[\"nextval('sequence_user_seq'::regclass)\"]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"handle\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":[\"VarChar\",[\"50\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"handle_lower\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":[\"VarChar\",[\"50\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"modify_date\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":[\"Timestamp\",[\"6\"]],\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"status\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":[\"VarChar\",[\"3\"]],\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"email\":{\"dbName\":\"email\",\"schema\":\"identity\",\"fields\":[{\"name\":\"email_id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Decimal\",\"nativeType\":[\"Decimal\",[\"10\",\"0\"]],\"default\":{\"name\":\"dbgenerated\",\"args\":[\"nextval('sequence_email_seq'::regclass)\"]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"user_id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Decimal\",\"nativeType\":[\"Decimal\",[\"10\",\"0\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"address\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":[\"VarChar\",[\"100\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"modify_date\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":[\"Timestamp\",[\"6\"]],\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"security_user\":{\"dbName\":\"security_user\",\"schema\":\"identity\",\"fields\":[{\"name\":\"login_id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Decimal\",\"nativeType\":[\"Decimal\",[\"12\",\"0\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"user_id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":true,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":[\"VarChar\",[\"50\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"password\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":[\"VarChar\",[\"300\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"create_user_id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Decimal\",\"nativeType\":[\"Decimal\",[\"12\",\"0\"]],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"modify_date\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"DateTime\",\"nativeType\":[\"Timestamp\",[\"6\"]],\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false}},\"enums\":{},\"types\":{}}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
The user_id field in the security_user model is marked as unique, which is correct for ensuring each user has a distinct entry. However, ensure that the application logic enforces this uniqueness to prevent potential data integrity issues.

}

model security_user {
login_id Decimal @id(map: "pk_security_user") @identitydb.Decimal(12, 0)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 readability]
Consider using a more descriptive name for login_id to clarify its purpose, especially since it is the primary key. This can improve readability and maintainability.

model security_user {
login_id Decimal @id(map: "pk_security_user") @identitydb.Decimal(12, 0)
user_id String @unique(map: "security_user_i2") @identitydb.VarChar(50)
password String @identitydb.VarChar(300)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ security]
Storing passwords as plain strings is a security risk. Ensure that passwords are hashed and salted before storage to protect user credentials.

model security_user {
login_id Decimal @id(map: "pk_security_user") @identitydb.Decimal(12, 0)
user_id String @unique(map: "security_user_i2") @identitydb.VarChar(50)
password String @identitydb.VarChar(300)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ security]
Consider using a more secure method for storing passwords, such as hashing with a strong algorithm (e.g., bcrypt) instead of storing them as plain strings. This will enhance the security of user credentials.

'Handle must be 3-64 characters long and can only contain alphanumeric characters and _.-`[]{} symbols.'
)
}
if (HANDLE_PUNCTUATION_ONLY_REGEX.test(handle)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
The regex HANDLE_PUNCTUATION_ONLY_REGEX allows for handles that are entirely punctuation, which is then immediately invalidated by the subsequent check. Consider revising the regex or removing this check if it's not needed.

if (existingIdentity && Number(existingIdentity.user_id) !== identityUserId) {
throw new errors.BadRequestError(`Handle "${newHandle}" is already registered`)
}
const existingSecurityUser = await identityPrisma.security_user.findUnique({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ correctness]
The existingSecurityUser check uses user_id as the lookup key, which is the new handle. Ensure that user_id is the correct field to use for this lookup, as it might cause incorrect behavior if user_id is not unique or not the intended field.


await updateVanillaHandle(member.handle, newHandle, vanillaPool)
vanillaUpdated = true
try {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
The updateVanillaHandle call is wrapped in a try-catch block, which logs a warning if an error occurs. Consider whether this error should be handled more robustly, as failing to update the Vanilla handle might lead to inconsistencies.

SET user_id=${newHandle}
WHERE user_id=${oldHandle}
`
const securityUserResult = await tx.security_user.updateMany({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ correctness]
The updateMany operation on security_user might not update any records if the where condition doesn't match any entries. Ensure that this behavior is intended and that the error handling logic is sufficient.

@jmgasper jmgasper merged commit ef0e3ef into master Jan 29, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants