main
ts 65 lines 2.82 KB
Raw
1 import { getCurrentUsername, setLoggedIn } from './auth'
2 import { BASIC_AUTHENTICATE_HEADER, HTTP_UNAUTHORIZED } from './cross-const'
3 import Koa from 'koa'
4 import { defineConfig } from './config'
5 import { getNodeName, getDefaultFile, nodeIsFolder, VfsNode, walkNode } from './vfs'
6 import { asyncGeneratorToReadable, Dict, escapeHTML, filterMapGenerator, pathEncode } from './misc'
7 import _ from 'lodash'
8 import { title } from './adminApis'
9 import { getSection } from './customHtml'
10
11 const autoBasic = defineConfig<boolean|string, null|RegExp>('auto_basic', true, v => _.isString(v) ? new RegExp(v, 'i') : null)
12
13 export function basicWeb(ctx: Koa.Context, node: VfsNode) {
14 const { get } = ctx.query
15 if (get === 'login') {
16 if (getCurrentUsername(ctx))
17 ctx.redirect(ctx.get('referer'))
18 else {
19 ctx.set('WWW-Authenticate', BASIC_AUTHENTICATE_HEADER)
20 ctx.status = HTTP_UNAUTHORIZED
21 }
22 return true
23 }
24 if (get === 'logout') {
25 ctx.body = `<script>location = ${JSON.stringify(ctx.get('referer'))}</script>`
26 setLoggedIn(ctx, false)
27 ctx.status = HTTP_UNAUTHORIZED // not effective on firefox52, but the redirection is
28 return true
29 }
30 const forced = get === 'basic'
31 const goBasic = forced || detectBasicAgent(ctx) && get !== 'nobasic'
32 if (!goBasic) return
33 ctx.type = 'html'
34 const force = forced ? '?get=basic' : ''
35 const walker = walkNode(node, { ctx, depth: 0 })
36 const stream = asyncGeneratorToReadable(filterMapGenerator(walker, async el => {
37 const isFolder = nodeIsFolder(el)
38 const name = getNodeName(el) + (isFolder ? '/' : '')
39 return `<li>${a(pathEncode(name) + (isFolder && !await getDefaultFile(el, ctx) ? force : ''), name)}\n`
40 }))
41 ctx.body = stream
42 stream.push(`<meta name="viewport" content="width=device-width" />`)
43 stream.push(`<style>body { font-size: 16pt; }</style>`)
44 stream.push(`<title>${title.get()}</title><body>`)
45 stream.push(getSection('basicHeader'))
46 const u = getCurrentUsername(ctx)
47 const links: Dict<string> = u ? { [`//LOGOUT%00:@${ctx.host}/?get=logout`]: `Logout (${u})` } : { '/?get=login': "Login" }
48 stream.push(_.map(links, (v,k) => a(k, v)).join(' ') + '\n<ul>\n')
49 if (ctx.state.originalPath.length > 1)
50 stream.push('<li>' + a('..' + force, '..') + '\n')
51 stream.on('ending', () =>
52 stream.push('</ul>\n' + getSection('basicFooter')) )
53 return true
54
55 function a(href: string, label: string) {
56 return `<a href='${href}'>${escapeHTML(label)}</a>`
57 }
58
59 }
60
61 export function detectBasicAgent(ctx: Koa.Context) {
62 const ua = ctx.get('user-agent')
63 return autoBasic.get() && /^$|Mozilla\/4|WebKit\/([234]\d\d|5[012]\d|53[0123456])[. ]|Trident|Lynx|curl|Firefox\/(\d|[1234]\d)\./.test(ua)
64 || autoBasic.compiled()?.test(ua)
65 }