You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
3.3 KiB
131 lines
3.3 KiB
import * as crypto from 'crypto'
|
|
import { models } from './models'
|
|
import * as cryptoJS from 'crypto-js'
|
|
import { success, failure } from './utils/res'
|
|
import { setInMemoryMacaroon } from './utils/macaroon'
|
|
import { loadConfig } from './utils/config'
|
|
const fs = require('fs')
|
|
|
|
const config = loadConfig()
|
|
|
|
/*
|
|
"unlock": true,
|
|
"encrypted_macaroon_path": "/relay/.lnd/admin.macaroon.enc"
|
|
*/
|
|
|
|
export async function unlocker(req, res): Promise<boolean> {
|
|
const { password } = req.body
|
|
if (!password) {
|
|
failure(res, 'no password')
|
|
return false
|
|
}
|
|
|
|
const encMacPath = config.encrypted_macaroon_path
|
|
if (!encMacPath) {
|
|
failure(res, 'no macaroon path')
|
|
return false
|
|
}
|
|
|
|
let hexMac: string
|
|
|
|
try {
|
|
|
|
var encMac = fs.readFileSync(config.encrypted_macaroon_path, "utf8");
|
|
if (!encMac) {
|
|
failure(res, 'no macaroon')
|
|
return false
|
|
}
|
|
|
|
console.log("PWD", password, typeof password)
|
|
console.log("ENCMAC", encMac, typeof encMac)
|
|
const decMac = decryptMacaroon(password, encMac)
|
|
if (!decMac) {
|
|
failure(res, 'failed to decrypt macaroon')
|
|
return false
|
|
}
|
|
|
|
hexMac = base64ToHex(decMac)
|
|
|
|
} catch (e) {
|
|
failure(res, e)
|
|
return false
|
|
}
|
|
|
|
if (hexMac) {
|
|
setInMemoryMacaroon(hexMac)
|
|
success(res, 'success!')
|
|
return true
|
|
} else {
|
|
failure(res, 'failed to set macaroon in memory')
|
|
return false
|
|
}
|
|
}
|
|
|
|
export async function authModule(req, res, next) {
|
|
if (
|
|
req.path == '/app' ||
|
|
req.path == '/' ||
|
|
req.path == '/unlock' ||
|
|
req.path == '/info' ||
|
|
req.path == '/action' ||
|
|
req.path == '/contacts/tokens' ||
|
|
req.path == '/latest' ||
|
|
req.path.startsWith('/static') ||
|
|
req.path == '/contacts/set_dev'
|
|
) {
|
|
next()
|
|
return
|
|
}
|
|
|
|
if (process.env.HOSTING_PROVIDER === 'true') {
|
|
// const domain = process.env.INVITE_SERVER
|
|
const host = req.headers.origin
|
|
console.log('=> host:', host)
|
|
const referer = req.headers.referer
|
|
console.log('=> referer:', referer)
|
|
if (req.path === '/invoices') {
|
|
next()
|
|
return
|
|
}
|
|
}
|
|
|
|
const token = req.headers['x-user-token'] || req.cookies['x-user-token']
|
|
|
|
if (token == null) {
|
|
res.writeHead(401, 'Access invalid for user', { 'Content-Type': 'text/plain' });
|
|
res.end('Invalid credentials');
|
|
} else {
|
|
const user = await models.Contact.findOne({ where: { isOwner: true } })
|
|
const hashedToken = crypto.createHash('sha256').update(token).digest('base64');
|
|
if (user.authToken == null || user.authToken != hashedToken) {
|
|
res.writeHead(401, 'Access invalid for user', { 'Content-Type': 'text/plain' });
|
|
res.end('Invalid credentials');
|
|
} else {
|
|
next();
|
|
}
|
|
}
|
|
}
|
|
|
|
function decryptMacaroon(password: string, macaroon: string) {
|
|
try {
|
|
const decrypted = cryptoJS.AES.decrypt(macaroon || '', password).toString(cryptoJS.enc.Base64)
|
|
const decryptResult = atob(decrypted)
|
|
return decryptResult
|
|
} catch (e) {
|
|
console.error('cipher mismatch, macaroon decryption failed')
|
|
console.error(e)
|
|
return ''
|
|
}
|
|
}
|
|
|
|
export function base64ToHex(str) {
|
|
const raw = atob(str)
|
|
let result = ''
|
|
for (let i = 0; i < raw.length; i++) {
|
|
const hex = raw.charCodeAt(i).toString(16)
|
|
result += (hex.length === 2 ? hex : '0' + hex)
|
|
}
|
|
return result.toUpperCase()
|
|
}
|
|
|
|
const atob = a => Buffer.from(a, 'base64').toString('binary')
|
|
|