/
Prefs.js
132 lines (111 loc) · 3.2 KB
/
Prefs.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
const path = require('path')
const db = require('sqlite')
const sql = require('sqlate')
const crypto = require('crypto')
const log = require('../lib/logger')('Prefs')
class Prefs {
/**
* Gets prefs (includes media paths, does not inlcude JWT secret key)
* @return {Promise} Prefs object
*/
static async get () {
const prefs = {
paths: { result: [], entities: {} }
}
{
const query = sql`
SELECT * FROM prefs
`
const rows = await db.all(String(query), query.parameters)
// json-decode key/val pairs
rows.forEach(row => {
prefs[row.key] = JSON.parse(row.data)
})
}
// include media paths
{
const query = sql`
SELECT * FROM paths
ORDER BY priority
`
const rows = await db.all(String(query), query.parameters)
for (const row of rows) {
prefs.paths.entities[row.pathId] = row
prefs.paths.result.push(row.pathId)
}
}
return prefs
}
/**
* Add media path
* @param {string} dir Absolute path
* @return {Promise} pathId (Number) of newly-added path
*/
static async addPath (dir) {
const prefs = await Prefs.get()
const { result, entities } = prefs.paths
// is it a subfolder of an already-added folder?
if (result.some(pathId => (dir + path.sep).indexOf(entities[pathId].path + path.sep) === 0)) {
throw new Error('Folder has already been added')
}
const fields = new Map()
fields.set('path', dir)
// priority defaults to one higher than current highest
fields.set('priority', result.length ? entities[result[result.length - 1]].priority + 1 : 0)
const query = sql`
INSERT INTO paths ${sql.tuple(Array.from(fields.keys()).map(sql.column))}
VALUES ${sql.tuple(Array.from(fields.values()))}
`
const res = await db.run(String(query), query.parameters)
if (!Number.isInteger(res.stmt.lastID)) {
throw new Error('invalid lastID from path insert')
}
// return pathId
return res.stmt.lastID
}
/**
* Remove media path
* @param {Number} pathId
* @return {Promise}
*/
static async removePath (pathId) {
const query = sql`
DELETE FROM paths
WHERE pathId = ${pathId}
`
await db.run(String(query), query.parameters)
}
/**
* Get JWT secret key from db
* @return {Promise} jwtKey (string)
*/
static async getJwtKey () {
const query = sql`
SELECT * FROM prefs
WHERE key = "jwtKey"
`
const row = await db.get(String(query), query.parameters)
if (row && row.data) {
const jwtKey = JSON.parse(row.data)
if (jwtKey.length === 64) {
return jwtKey
}
}
return this.jwtKeyRefresh()
}
/**
* Create or rotate JWT secret key
* @return {Promise} jwtKey (string)
*/
static async jwtKeyRefresh () {
const jwtKey = crypto.randomBytes(48).toString('base64') // 64 char
log.info('Rotating JWT secret key (length=%s)', jwtKey.length)
const query = sql`
REPLACE INTO prefs (key, data)
VALUES ("jwtKey", ${JSON.stringify(jwtKey)})
`
const res = await db.run(String(query), query.parameters)
if (res.stmt.changes) return jwtKey
}
}
module.exports = Prefs