feat(auth): sign in with Steam (MODULE_API 1.17.0)
Steam is a built-in provider beside Google and Discord (STEAM_SIGNIN.md, D392-D396). OpenID 2.0: the assertion is verified server to server with check_authentication, return_to must match byte for byte, and the claimed id must be a 17-digit SteamID64. A Steam Web API key is required to enable it (D394); persona name and avatar are stored on the identity and refreshed at each sign-in, and a failed lookup never blocks one. Steam never signs anybody up (D395), on the web or the mobile bridge. Several Steam accounts may be linked; DELETE /auth/me/account/identities/:provider takes ?id= to unlink one. MODULE_API 1.17.0: ctx.identities.list, api.onIdentityLinking (refuse-only, fails closed, module text never shown) and api.onIdentityLinked. No unlink hook (D393). Schema additive; OpenAPI, routes and engagement manifests regenerated with no modules installed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -13,21 +13,45 @@ async function findByProviderSubject(provider, subject) {
|
||||
// All identities linked to a given internal user (for the Account page).
|
||||
async function listForUser(userId) {
|
||||
return query(
|
||||
'SELECT id, provider, subject, email, created_at FROM user_identities WHERE user_id = ? ORDER BY provider',
|
||||
`SELECT id, provider, subject, email, display_name, avatar_url, created_at
|
||||
FROM user_identities WHERE user_id = ? ORDER BY provider, created_at`,
|
||||
[userId],
|
||||
)
|
||||
}
|
||||
|
||||
async function insert({ userId, provider, subject, email = null }) {
|
||||
async function insert({ userId, provider, subject, email = null, displayName = null, avatarUrl = null }) {
|
||||
const res = await query(
|
||||
'INSERT INTO user_identities (user_id, provider, subject, email) VALUES (?, ?, ?, ?)',
|
||||
[userId, provider, subject, email],
|
||||
`INSERT INTO user_identities (user_id, provider, subject, email, display_name, avatar_url)
|
||||
VALUES (?, ?, ?, ?, ?, ?)`,
|
||||
[userId, provider, subject, email, displayName, avatarUrl],
|
||||
)
|
||||
return res.insertId
|
||||
}
|
||||
|
||||
// Remove a user's link to a provider. Returns rows deleted.
|
||||
async function deleteForUserProvider(userId, provider) {
|
||||
// Refresh the name and avatar a provider reported at sign-in (Steam, D394). Only
|
||||
// what the provider sent is written: a lookup that failed leaves the last good
|
||||
// values in place rather than blanking them.
|
||||
async function updateProfile(id, { displayName, avatarUrl }) {
|
||||
const sets = []
|
||||
const vals = []
|
||||
if (displayName) { sets.push('display_name = ?'); vals.push(displayName) }
|
||||
if (avatarUrl) { sets.push('avatar_url = ?'); vals.push(avatarUrl) }
|
||||
if (!sets.length) return 0
|
||||
const res = await query(`UPDATE user_identities SET ${sets.join(', ')} WHERE id = ?`, [...vals, id])
|
||||
return Number(res.affectedRows || 0)
|
||||
}
|
||||
|
||||
// Remove a user's link to a provider — every identity of it, or, given an
|
||||
// identity id, that one only (a user may hold several Steam accounts). Returns
|
||||
// rows deleted.
|
||||
async function deleteForUserProvider(userId, provider, identityId = null) {
|
||||
if (identityId != null) {
|
||||
const res = await query(
|
||||
'DELETE FROM user_identities WHERE user_id = ? AND provider = ? AND id = ?',
|
||||
[userId, provider, identityId],
|
||||
)
|
||||
return Number(res.affectedRows || 0)
|
||||
}
|
||||
const res = await query(
|
||||
'DELETE FROM user_identities WHERE user_id = ? AND provider = ?',
|
||||
[userId, provider],
|
||||
@@ -35,4 +59,4 @@ async function deleteForUserProvider(userId, provider) {
|
||||
return Number(res.affectedRows || 0)
|
||||
}
|
||||
|
||||
module.exports = { findByProviderSubject, listForUser, insert, deleteForUserProvider }
|
||||
module.exports = { findByProviderSubject, listForUser, insert, updateProfile, deleteForUserProvider }
|
||||
|
||||
Reference in New Issue
Block a user