--create-admin <password>
Massimo Melina committed
Jun 8, 2022 at 22:31 UTC
0e836a05d0e1afb98d135a4af4aa0b8c327ab4cb
5 files changed
+30
-21
README.md
+6
-12
@@ -39,21 +39,15 @@ You won't find all previous features here (yet), but still we got:
39
4. launch `hfs` file
40
5. the browser should automatically open on `localhost` address, so you can configure the rest
41
42
+If you access HFS via localhost, by default it won't require your to login.
43
+
44
### Cloud server?
45
46
If you are installing HFS on "another" machine, then step 5 may not be possible.
45
-In this case you should create a `config.yaml` file with this content:
46
-```
47
-accounts:
48
- YOUR-USERNAME:
49
- admin: true
50
- password: YOUR-PASSWORD
51
-```
52
-
53
-This way you'll have your admin account.
54
-Be sure to respect spaces/indentation.
55
-
56
-Don't worry about the password, it will be encrypted at first run.
47
+In this case you should run hfs with `--create-admin <PASSWORD>`.
48
+This will both
49
+- create an account with username `admin` with the provided password and Admin privilege (granting access to Admin panel).
50
+- disable the unprotected access (no login) to Admin panel
51
52
### Other systems
53
server/src/config.ts
+2
@@ -9,6 +9,7 @@ import { debounceAsync, same, objSameKeys, onOff, wait, with_ } from './misc'
9
import { exists, statSync } from 'fs'
10
import { promisify } from 'util'
11
import { join } from 'path'
12
+import events from './events'
13
14
const PATH = 'config.yaml'
15
@@ -115,6 +116,7 @@ export function setConfig(newCfg: Record<string,any>, save?: boolean) {
116
if (!newCfg.hasOwnProperty(k))
117
apply(k, newCfg[k])
118
started = true
119
+ events.emit('config ready')
120
121
function apply(k: string, newV: any) {
122
return setConfig1(k, newV, save === undefined)
server/src/misc.ts
+2
-2
@@ -37,12 +37,12 @@ export function prefix(pre:string, v:string|number, post:string='') {
37
return v ? pre+v+post : ''
38
}
39
40
-export function setHidden(dest: object, src:object) {
40
+export function setHidden<T, ADD>(dest: T, src: ADD) {
41
return Object.defineProperties(dest, objSameKeys(src as any, value => ({
42
enumerable: false,
43
writable: true,
44
value,
45
- })))
45
+ }))) as T & ADD
46
}
47
48
export function objSameKeys<S extends object,VR=any>(src: S, newValue:(value:Truthy<S[keyof S]>, key:keyof S)=>any) {
server/src/perm.ts
+20
-6
@@ -7,6 +7,8 @@ import Koa from 'koa'
7
import { defineConfig, saveConfigAsap } from './config'
8
import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
9
import events from './events'
10
+import { argv } from './const'
11
+import { localhostAdmin } from './adminApis'
12
13
export interface Account {
14
username: string, // we'll have username in it, so we don't need to pass it separately
@@ -98,6 +100,15 @@ accountsConfig.sub(async v => {
100
}))
101
})
102
103
+events.once('config ready', async () => {
104
+ const pwd = argv['create-admin']
105
+ if (!pwd) return
106
+ const acc = getAccount('admin') || addAccount('admin', { admin: true })
107
+ await updateAccount(acc!, acc => acc.password = pwd)
108
+ localhostAdmin.set(false)
109
+ console.log("account 'admin' created while unprotected admin access on localhost is now disabled")
110
+})
111
+
112
function normalizeUsername(username: string) {
113
return username.toLocaleLowerCase()
114
}
@@ -131,23 +142,26 @@ const assignableProps: (keyof Account)[] = ['redirect','ignore_limits','belongs'
142
export function addAccount(username: string, props: Partial<Account>) {
143
if (!username || accounts[username])
144
return
134
- const copy = _.pickBy(_.pick(props, assignableProps), Boolean)
135
- setHidden(copy, { username })
145
+ const copy: Account = setHidden(_.pickBy(_.pick(props, assignableProps), Boolean),
146
+ { username }) // have the field in the object but hidden so that stringification won't include it
147
accountsConfig.set(accounts =>
148
Object.assign(accounts, { [username]: copy }))
138
- saveAccountsAsap()
149
+ saveAccountsAsap().then()
150
return copy
151
}
152
153
export function setAccount(username: string, changes: Partial<Account>) {
154
+ const acc = getAccount(username)
155
+ if (!acc)
156
+ return false
157
const rest = _.pick(changes, assignableProps)
158
for (const [k,v] of Object.entries(rest))
159
if (!v)
160
rest[k as keyof Account] = undefined
147
- Object.assign(getAccount(username), rest)
161
+ Object.assign(acc, rest)
162
if (changes.username)
163
renameAccount(username, changes.username)
150
- saveAccountsAsap()
164
+ saveAccountsAsap().then()
165
return true
166
}
167
@@ -156,7 +170,7 @@ export function delAccount(username: string) {
170
return false
171
accountsConfig.set(accounts =>
172
Object.assign(accounts, { [username]: undefined }))
159
- saveAccountsAsap()
173
+ saveAccountsAsap().then()
174
return true
175
}
176
todo.md
-1
@@ -1,7 +1,6 @@
1
# To do
2
- fix: root without can_download breaks
3
- use dialogs instead of side-forms on mobile (admin/fs+accounts)
4
-- easier deploy on cloud server: --create-admin <password>
4
- admin/fs: sort items
5
- admin/fs: render virtual folders differently
6
- admin/config: hide advanced settings