mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
## Description This PR adds a new method of protecting a user profile when switching to it: server login. When enabled, switching to the user requires authenticating with the server again via Quick Connect or username & password. This is basically the same as the official client. ### Related issues Closes #321 Related to #1330 - might cause merge conflicts Related to #1287 - definitely causes merge conflicts ### Testing Emulator with various uses cases including auto sign-in, switching between server login & PIN protection, and removing the protection ## Screenshots N/A, the login looks identical as adding a new user ## AI or LLM usage None
659 lines
19 KiB
JSON
659 lines
19 KiB
JSON
{
|
|
"formatVersion": 1,
|
|
"database": {
|
|
"version": 32,
|
|
"identityHash": "934c38e7f4eb68c9a223ddb5c7e3e35d",
|
|
"entities": [
|
|
{
|
|
"tableName": "servers",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT, `url` TEXT NOT NULL, `version` TEXT, `lastUsed` TEXT, PRIMARY KEY(`id`))",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "id",
|
|
"columnName": "id",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "name",
|
|
"columnName": "name",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "url",
|
|
"columnName": "url",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "version",
|
|
"columnName": "version",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "lastUsed",
|
|
"columnName": "lastUsed",
|
|
"affinity": "TEXT"
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": false,
|
|
"columnNames": [
|
|
"id"
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"tableName": "users",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `id` TEXT NOT NULL, `name` TEXT, `serverId` TEXT NOT NULL, `accessToken` TEXT, `pin` TEXT, `requireLogin` INTEGER NOT NULL DEFAULT false, `lastUsed` TEXT, FOREIGN KEY(`serverId`) REFERENCES `servers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "rowId",
|
|
"columnName": "rowId",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "id",
|
|
"columnName": "id",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "name",
|
|
"columnName": "name",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "serverId",
|
|
"columnName": "serverId",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "accessToken",
|
|
"columnName": "accessToken",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "pin",
|
|
"columnName": "pin",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "requireLogin",
|
|
"columnName": "requireLogin",
|
|
"affinity": "INTEGER",
|
|
"notNull": true,
|
|
"defaultValue": "false"
|
|
},
|
|
{
|
|
"fieldPath": "lastUsed",
|
|
"columnName": "lastUsed",
|
|
"affinity": "TEXT"
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": true,
|
|
"columnNames": [
|
|
"rowId"
|
|
]
|
|
},
|
|
"indices": [
|
|
{
|
|
"name": "index_users_id_serverId",
|
|
"unique": true,
|
|
"columnNames": [
|
|
"id",
|
|
"serverId"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_users_id_serverId` ON `${TABLE_NAME}` (`id`, `serverId`)"
|
|
},
|
|
{
|
|
"name": "index_users_id",
|
|
"unique": false,
|
|
"columnNames": [
|
|
"id"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_users_id` ON `${TABLE_NAME}` (`id`)"
|
|
},
|
|
{
|
|
"name": "index_users_serverId",
|
|
"unique": false,
|
|
"columnNames": [
|
|
"serverId"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_users_serverId` ON `${TABLE_NAME}` (`serverId`)"
|
|
}
|
|
],
|
|
"foreignKeys": [
|
|
{
|
|
"table": "servers",
|
|
"onDelete": "CASCADE",
|
|
"onUpdate": "NO ACTION",
|
|
"columns": [
|
|
"serverId"
|
|
],
|
|
"referencedColumns": [
|
|
"id"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "ItemPlayback",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `sourceId` TEXT, `audioIndex` INTEGER NOT NULL, `subtitleIndex` INTEGER NOT NULL, FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "rowId",
|
|
"columnName": "rowId",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "userId",
|
|
"columnName": "userId",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "itemId",
|
|
"columnName": "itemId",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "sourceId",
|
|
"columnName": "sourceId",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "audioIndex",
|
|
"columnName": "audioIndex",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "subtitleIndex",
|
|
"columnName": "subtitleIndex",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": true,
|
|
"columnNames": [
|
|
"rowId"
|
|
]
|
|
},
|
|
"indices": [
|
|
{
|
|
"name": "index_ItemPlayback_userId_itemId",
|
|
"unique": true,
|
|
"columnNames": [
|
|
"userId",
|
|
"itemId"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_ItemPlayback_userId_itemId` ON `${TABLE_NAME}` (`userId`, `itemId`)"
|
|
}
|
|
],
|
|
"foreignKeys": [
|
|
{
|
|
"table": "users",
|
|
"onDelete": "CASCADE",
|
|
"onUpdate": "CASCADE",
|
|
"columns": [
|
|
"userId"
|
|
],
|
|
"referencedColumns": [
|
|
"rowId"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "NavDrawerPinnedItem",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `type` TEXT NOT NULL, `order` INTEGER NOT NULL DEFAULT -1, PRIMARY KEY(`userId`, `itemId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "userId",
|
|
"columnName": "userId",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "itemId",
|
|
"columnName": "itemId",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "type",
|
|
"columnName": "type",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "order",
|
|
"columnName": "order",
|
|
"affinity": "INTEGER",
|
|
"notNull": true,
|
|
"defaultValue": "-1"
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": false,
|
|
"columnNames": [
|
|
"userId",
|
|
"itemId"
|
|
]
|
|
},
|
|
"foreignKeys": [
|
|
{
|
|
"table": "users",
|
|
"onDelete": "CASCADE",
|
|
"onUpdate": "CASCADE",
|
|
"columns": [
|
|
"userId"
|
|
],
|
|
"referencedColumns": [
|
|
"rowId"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "LibraryDisplayInfo",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `sort` TEXT NOT NULL, `direction` TEXT NOT NULL, `filter` TEXT NOT NULL DEFAULT '{}', `viewOptions` TEXT, PRIMARY KEY(`userId`, `itemId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "userId",
|
|
"columnName": "userId",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "itemId",
|
|
"columnName": "itemId",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "sort",
|
|
"columnName": "sort",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "direction",
|
|
"columnName": "direction",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "filter",
|
|
"columnName": "filter",
|
|
"affinity": "TEXT",
|
|
"notNull": true,
|
|
"defaultValue": "'{}'"
|
|
},
|
|
{
|
|
"fieldPath": "viewOptions",
|
|
"columnName": "viewOptions",
|
|
"affinity": "TEXT"
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": false,
|
|
"columnNames": [
|
|
"userId",
|
|
"itemId"
|
|
]
|
|
},
|
|
"indices": [
|
|
{
|
|
"name": "index_LibraryDisplayInfo_userId_itemId",
|
|
"unique": true,
|
|
"columnNames": [
|
|
"userId",
|
|
"itemId"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_LibraryDisplayInfo_userId_itemId` ON `${TABLE_NAME}` (`userId`, `itemId`)"
|
|
}
|
|
],
|
|
"foreignKeys": [
|
|
{
|
|
"table": "users",
|
|
"onDelete": "CASCADE",
|
|
"onUpdate": "CASCADE",
|
|
"columns": [
|
|
"userId"
|
|
],
|
|
"referencedColumns": [
|
|
"rowId"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "playback_effects",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`jellyfinUserRowId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `type` TEXT NOT NULL, `rotation` INTEGER NOT NULL, `brightness` INTEGER NOT NULL, `contrast` INTEGER NOT NULL, `saturation` INTEGER NOT NULL, `hue` INTEGER NOT NULL, `red` INTEGER NOT NULL, `green` INTEGER NOT NULL, `blue` INTEGER NOT NULL, `blur` INTEGER NOT NULL, PRIMARY KEY(`jellyfinUserRowId`, `itemId`, `type`))",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "jellyfinUserRowId",
|
|
"columnName": "jellyfinUserRowId",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "itemId",
|
|
"columnName": "itemId",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "type",
|
|
"columnName": "type",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "videoFilter.rotation",
|
|
"columnName": "rotation",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "videoFilter.brightness",
|
|
"columnName": "brightness",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "videoFilter.contrast",
|
|
"columnName": "contrast",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "videoFilter.saturation",
|
|
"columnName": "saturation",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "videoFilter.hue",
|
|
"columnName": "hue",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "videoFilter.red",
|
|
"columnName": "red",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "videoFilter.green",
|
|
"columnName": "green",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "videoFilter.blue",
|
|
"columnName": "blue",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "videoFilter.blur",
|
|
"columnName": "blur",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": false,
|
|
"columnNames": [
|
|
"jellyfinUserRowId",
|
|
"itemId",
|
|
"type"
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"tableName": "PlaybackLanguageChoice",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `seriesId` TEXT NOT NULL, `itemId` TEXT, `audioLanguage` TEXT, `subtitleLanguage` TEXT, `subtitlesDisabled` INTEGER, PRIMARY KEY(`userId`, `seriesId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "userId",
|
|
"columnName": "userId",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "seriesId",
|
|
"columnName": "seriesId",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "itemId",
|
|
"columnName": "itemId",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "audioLanguage",
|
|
"columnName": "audioLanguage",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "subtitleLanguage",
|
|
"columnName": "subtitleLanguage",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "subtitlesDisabled",
|
|
"columnName": "subtitlesDisabled",
|
|
"affinity": "INTEGER"
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": false,
|
|
"columnNames": [
|
|
"userId",
|
|
"seriesId"
|
|
]
|
|
},
|
|
"foreignKeys": [
|
|
{
|
|
"table": "users",
|
|
"onDelete": "CASCADE",
|
|
"onUpdate": "CASCADE",
|
|
"columns": [
|
|
"userId"
|
|
],
|
|
"referencedColumns": [
|
|
"rowId"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "ItemTrackModification",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `trackIndex` INTEGER NOT NULL, `delayMs` INTEGER NOT NULL, PRIMARY KEY(`userId`, `itemId`, `trackIndex`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "userId",
|
|
"columnName": "userId",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "itemId",
|
|
"columnName": "itemId",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "trackIndex",
|
|
"columnName": "trackIndex",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "delayMs",
|
|
"columnName": "delayMs",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": false,
|
|
"columnNames": [
|
|
"userId",
|
|
"itemId",
|
|
"trackIndex"
|
|
]
|
|
},
|
|
"foreignKeys": [
|
|
{
|
|
"table": "users",
|
|
"onDelete": "CASCADE",
|
|
"onUpdate": "CASCADE",
|
|
"columns": [
|
|
"userId"
|
|
],
|
|
"referencedColumns": [
|
|
"rowId"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "seerr_servers",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `name` TEXT, `version` TEXT)",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "id",
|
|
"columnName": "id",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "url",
|
|
"columnName": "url",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "name",
|
|
"columnName": "name",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "version",
|
|
"columnName": "version",
|
|
"affinity": "TEXT"
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": true,
|
|
"columnNames": [
|
|
"id"
|
|
]
|
|
},
|
|
"indices": [
|
|
{
|
|
"name": "index_seerr_servers_url",
|
|
"unique": true,
|
|
"columnNames": [
|
|
"url"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_seerr_servers_url` ON `${TABLE_NAME}` (`url`)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "seerr_users",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`jellyfinUserRowId` INTEGER NOT NULL, `serverId` INTEGER NOT NULL, `authMethod` TEXT NOT NULL, `username` TEXT, `password` TEXT, `credential` TEXT, PRIMARY KEY(`jellyfinUserRowId`, `serverId`), FOREIGN KEY(`serverId`) REFERENCES `seerr_servers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`jellyfinUserRowId`) REFERENCES `users`(`rowId`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "jellyfinUserRowId",
|
|
"columnName": "jellyfinUserRowId",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "serverId",
|
|
"columnName": "serverId",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "authMethod",
|
|
"columnName": "authMethod",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "username",
|
|
"columnName": "username",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "password",
|
|
"columnName": "password",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "credential",
|
|
"columnName": "credential",
|
|
"affinity": "TEXT"
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": false,
|
|
"columnNames": [
|
|
"jellyfinUserRowId",
|
|
"serverId"
|
|
]
|
|
},
|
|
"foreignKeys": [
|
|
{
|
|
"table": "seerr_servers",
|
|
"onDelete": "CASCADE",
|
|
"onUpdate": "NO ACTION",
|
|
"columns": [
|
|
"serverId"
|
|
],
|
|
"referencedColumns": [
|
|
"id"
|
|
]
|
|
},
|
|
{
|
|
"table": "users",
|
|
"onDelete": "CASCADE",
|
|
"onUpdate": "NO ACTION",
|
|
"columns": [
|
|
"jellyfinUserRowId"
|
|
],
|
|
"referencedColumns": [
|
|
"rowId"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"setupQueries": [
|
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '934c38e7f4eb68c9a223ddb5c7e3e35d')"
|
|
]
|
|
}
|
|
}
|