feat(database): make token column nullable in caldav_tokens table for improved flexibility
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m36s
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m36s
This commit is contained in:
@@ -49,6 +49,12 @@ class SqliteAdapter {
|
|||||||
return !!columns.find(c => c.name === column);
|
return !!columns.find(c => c.name === column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async columnIsNullable(table, column) {
|
||||||
|
const columns = this.db.pragma(`table_info(${table})`);
|
||||||
|
const col = columns.find(c => c.name === column);
|
||||||
|
return col ? col.notnull === 0 : true;
|
||||||
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.db.close();
|
this.db.close();
|
||||||
}
|
}
|
||||||
@@ -98,6 +104,14 @@ class PostgresAdapter {
|
|||||||
return result.rows.length > 0;
|
return result.rows.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async columnIsNullable(table, column) {
|
||||||
|
const result = await this.pool.query(
|
||||||
|
'SELECT is_nullable FROM information_schema.columns WHERE table_name = $1 AND column_name = $2',
|
||||||
|
[table, column]
|
||||||
|
);
|
||||||
|
return result.rows.length > 0 ? result.rows[0].is_nullable === 'YES' : true;
|
||||||
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.pool?.end();
|
this.pool?.end();
|
||||||
}
|
}
|
||||||
@@ -691,6 +705,34 @@ export async function initDatabase() {
|
|||||||
await db.exec('CREATE INDEX IF NOT EXISTS idx_caldav_tokens_hash ON caldav_tokens(token_hash)');
|
await db.exec('CREATE INDEX IF NOT EXISTS idx_caldav_tokens_hash ON caldav_tokens(token_hash)');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalDAV: make token column nullable (now only token_hash is stored for new tokens)
|
||||||
|
if (!(await db.columnIsNullable('caldav_tokens', 'token'))) {
|
||||||
|
if (isPostgres) {
|
||||||
|
await db.exec('ALTER TABLE caldav_tokens ALTER COLUMN token DROP NOT NULL');
|
||||||
|
} else {
|
||||||
|
// SQLite does not support ALTER COLUMN — recreate the table
|
||||||
|
await db.exec(`
|
||||||
|
CREATE TABLE caldav_tokens_new (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
token TEXT UNIQUE,
|
||||||
|
token_hash TEXT DEFAULT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
last_used_at DATETIME DEFAULT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO caldav_tokens_new (id, user_id, token, token_hash, name, created_at, last_used_at)
|
||||||
|
SELECT id, user_id, token, token_hash, name, created_at, last_used_at FROM caldav_tokens;
|
||||||
|
DROP TABLE caldav_tokens;
|
||||||
|
ALTER TABLE caldav_tokens_new RENAME TO caldav_tokens;
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_caldav_tokens_user_id ON caldav_tokens(user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_caldav_tokens_token ON caldav_tokens(token);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_caldav_tokens_hash ON caldav_tokens(token_hash);
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── OAuth tables ────────────────────────────────────────────────────────
|
// ── OAuth tables ────────────────────────────────────────────────────────
|
||||||
if (isPostgres) {
|
if (isPostgres) {
|
||||||
await db.exec(`
|
await db.exec(`
|
||||||
|
|||||||
@@ -752,7 +752,7 @@ router.post('/caldav-tokens', authenticateToken, async (req, res) => {
|
|||||||
const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
|
const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
|
||||||
const result = await db.run(
|
const result = await db.run(
|
||||||
// Store only the hash — never the plaintext — to limit exposure on DB breach.
|
// Store only the hash — never the plaintext — to limit exposure on DB breach.
|
||||||
'INSERT INTO caldav_tokens (user_id, token, token_hash, name) VALUES (?, NULL, ?, ?)',
|
'INSERT INTO caldav_tokens (user_id, token_hash, name) VALUES (?, ?, ?)',
|
||||||
[req.user.id, tokenHash, name.trim()],
|
[req.user.id, tokenHash, name.trim()],
|
||||||
);
|
);
|
||||||
res.status(201).json({
|
res.status(201).json({
|
||||||
|
|||||||
Reference in New Issue
Block a user