Merge pull request #510 from shocknet/new-auth

New Auth
This commit is contained in:
Daniel Lugo 2022-01-25 14:51:45 -04:00 committed by GitHub
commit 6a7c66711b
8 changed files with 618 additions and 594 deletions

View file

@ -8,8 +8,6 @@ MS_TO_TOKEN_EXPIRATION=4500000
SHOCK_ENCRYPTION_ECC=true SHOCK_ENCRYPTION_ECC=true
CACHE_HEADERS_MANDATORY=true CACHE_HEADERS_MANDATORY=true
SHOCK_CACHE=true SHOCK_CACHE=true
# Use only if disabling LND encrypt phrase (security risk)
TRUSTED_KEYS=true
# SSH Tunnel Provider # SSH Tunnel Provider
LOCAL_TUNNEL_SERVER=https://tunnel.rip LOCAL_TUNNEL_SERVER=https://tunnel.rip
# Default content to your own seed server # Default content to your own seed server

55
.vscode/settings.json vendored
View file

@ -6,25 +6,78 @@
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "esbenp.prettier-vscode",
"cSpell.words": [ "cSpell.words": [
"acked", "acked",
"addinvoice",
"Authing", "Authing",
"channelbalance",
"ciphertext", "ciphertext",
"closechannel",
"closedchannels",
"Cltv",
"connectpeer",
"disconnectpeer",
"eccrypto", "eccrypto",
"endregion", "endregion",
"ephem", "ephem",
"epriv", "epriv",
"Epub", "Epub",
"estimatefee",
"estimateroutefee",
"exportallchanbackups",
"exportchanbackup",
"falsey", "falsey",
"forwardinghistory",
"getchaninfo",
"getinfo",
"getnetworkinfo",
"getnodeinfo",
"GUNRPC", "GUNRPC",
"Healthz",
"initwall",
"ISEA", "ISEA",
"keysend",
"kubernetes",
"listchannels",
"listinvoices",
"listpayments",
"listpeers",
"listunspent",
"lndchanbackups",
"LNDRPC", "LNDRPC",
"lndstreaming", "lndstreaming",
"lnrpc",
"lres",
"msgpack",
"newaddress",
"openchannel",
"otheruser",
"payreq",
"pendingchannels",
"preimage",
"PUBKEY", "PUBKEY",
"qrcode",
"queryroute",
"radata", "radata",
"Reqs", "Reqs",
"resave",
"satoshis",
"sendcoins",
"sendmany",
"sendpayment",
"sendtoroute",
"serverhost",
"serverport",
"shockping", "shockping",
"SHOCKWALLET", "SHOCKWALLET",
"signmessage",
"thenables", "thenables",
"trackpayment",
"txid",
"unfollow",
"Unlocker",
"unsubscription", "unsubscription",
"uuidv" "utxos",
"uuidv",
"verifymessage",
"walletbalance"
] ]
} }

View file

@ -13,5 +13,4 @@ services:
- 9835:9835 - 9835:9835
volumes: volumes:
- C:\Users\boufn\.polar\networks\2\volumes\lnd\alice:/root/.lnd - C:\Users\boufn\.polar\networks\2\volumes\lnd\alice:/root/.lnd
environment:
TRUSTED_KEYS: 'false'

View file

@ -22,7 +22,7 @@ const Getters = require('./getters')
const Key = require('./key') const Key = require('./key')
const Utils = require('./utils') const Utils = require('./utils')
const SchemaManager = require('../../schema') const SchemaManager = require('../../schema')
const LNDHealthMananger = require('../../../utils/lightningServices/errors') const LNDHealthManager = require('../../../utils/lightningServices/errors')
const { enrollContentTokens, selfContentToken } = require('../../seed') const { enrollContentTokens, selfContentToken } = require('../../seed')
/// <reference path="../../../utils/GunSmith/Smith.ts" /> /// <reference path="../../../utils/GunSmith/Smith.ts" />
@ -305,7 +305,7 @@ const setCurrentStreamInfo = (encryptedCurrentStreamInfo, user) =>
}) })
/** /**
* @typedef {object} SpontPaymentOptions * @typedef {object} SpontaneousPaymentOptions
* @prop {Common.Schema.OrderTargetType} type * @prop {Common.Schema.OrderTargetType} type
* @prop {string=} ackInfo * @prop {string=} ackInfo
*/ */
@ -320,7 +320,7 @@ const setCurrentStreamInfo = (encryptedCurrentStreamInfo, user) =>
* @param {number} amount * @param {number} amount
* @param {string} memo * @param {string} memo
* @param {number} feeLimit * @param {number} feeLimit
* @param {SpontPaymentOptions} opts * @param {SpontaneousPaymentOptions} opts
* @throws {Error} If no response in less than 20 seconds from the recipient, or * @throws {Error} If no response in less than 20 seconds from the recipient, or
* lightning cannot find a route for the payment. * lightning cannot find a route for the payment.
* @returns {Promise<OrderRes>} The payment's preimage. * @returns {Promise<OrderRes>} The payment's preimage.
@ -498,7 +498,7 @@ const sendSpontaneousPayment = async (
feeLimit, feeLimit,
payment_request: orderResponse.response payment_request: orderResponse.response
}) })
const myLndPub = LNDHealthMananger.lndPub const myLndPub = LNDHealthManager.lndPub
if ( if (
(opts.type !== 'contentReveal' && (opts.type !== 'contentReveal' &&
opts.type !== 'torrentSeed' && opts.type !== 'torrentSeed' &&

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,21 @@
/** /**
* @prettier * @prettier
*/ */
// @ts-check
const ECCrypto = require('eccrypto')
const ECC = require('../utils/ECC')
/**
* This API run's private key.
*/
const runPrivateKey = ECCrypto.generatePrivate()
/**
* This API run's public key.
*/
const runPublicKey = ECCrypto.getPublic(runPrivateKey)
process.on('uncaughtException', e => { process.on('uncaughtException', e => {
console.log('something bad happened!') console.log('something bad happened!')
console.log(e) console.log(e)
@ -20,7 +35,6 @@ const server = program => {
const { Logger: CommonLogger } = require('shock-common') const { Logger: CommonLogger } = require('shock-common')
const binaryParser = require('socket.io-msgpack-parser') const binaryParser = require('socket.io-msgpack-parser')
const ECC = require('../utils/ECC')
const LightningServices = require('../utils/lightningServices') const LightningServices = require('../utils/lightningServices')
const app = Express() const app = Express()
@ -31,11 +45,17 @@ const server = program => {
const qrcode = require('qrcode-terminal') const qrcode = require('qrcode-terminal')
const relayClient = require('hybrid-relay-client/build') const relayClient = require('hybrid-relay-client/build')
const { const {
unprotectedRoutes,
sensitiveRoutes, sensitiveRoutes,
nonEncryptedRoutes nonEncryptedRoutes
} = require('../utils/protectedRoutes') } = require('../utils/protectedRoutes')
/**
* An offline-only private key used for authenticating a client's key
* exchange. Neither the tunnel nor the WWW should see this private key, it
* should only be served through STDOUT (via QR or else).
*/
const accessSecret = program.tunnel ? ECCrypto.generatePrivate() : null
// load app default configuration data // load app default configuration data
const defaults = require('../config/defaults')(program.mainnet) const defaults = require('../config/defaults')(program.mainnet)
const rootFolder = program.rootPath || process.resourcesPath || __dirname const rootFolder = program.rootPath || process.resourcesPath || __dirname
@ -82,41 +102,6 @@ const server = program => {
.digest('hex') .digest('hex')
} }
const cacheCheck = ({ req, res, args, send }) => {
if (
(process.env.SHOCK_CACHE === 'true' || !process.env.SHOCK_CACHE) &&
req.method === 'GET'
) {
const dataHash = hashData(args[0]).slice(-8)
res.set('shock-cache-hash', dataHash)
logger.debug('shock-cache-hash:', req.headers['shock-cache-hash'])
logger.debug('Data Hash:', dataHash)
if (
!req.headers['shock-cache-hash'] &&
(process.env.CACHE_HEADERS_MANDATORY === 'true' ||
!process.env.CACHE_HEADERS_MANDATORY)
) {
logger.warn(
"Request is missing 'shock-cache-hash' header, please make sure to include that in each GET request in order to benefit from reduced data usage"
)
return { cached: false, hash: dataHash }
}
if (req.headers['shock-cache-hash'] === dataHash) {
logger.debug('Same Hash Detected!')
args[0] = null
res.status(304)
send.apply(res, args)
return { cached: true, hash: dataHash }
}
return { cached: false, hash: dataHash }
}
return { cached: false, hash: null }
}
/** /**
* @param {Express.Request} req * @param {Express.Request} req
* @param {Express.Response} res * @param {Express.Response} res
@ -140,6 +125,7 @@ const server = program => {
return return
} }
// @ts-expect-error
res.send = (...args) => { res.send = (...args) => {
if (args[0] && args[0].ciphertext && args[0].iv) { if (args[0] && args[0].ciphertext && args[0].iv) {
logger.warn('Response loop detected!') logger.warn('Response loop detected!')
@ -147,20 +133,23 @@ const server = program => {
return return
} }
const authorized = ECC.isAuthorizedDevice({ if (typeof deviceId !== 'string' || !deviceId) {
deviceId // TODO
}) }
const authorized = ECC.devicePublicKeys.has(deviceId)
// Using classic promises syntax to avoid // Using classic promises syntax to avoid
// modifying res.send's return type // modifying res.send's return type
if (authorized && process.env.SHOCK_ENCRYPTION_ECC !== 'false') { if (authorized && process.env.SHOCK_ENCRYPTION_ECC !== 'false') {
ECC.encryptMessage({ const devicePub = Buffer.from(ECC.devicePublicKeys.get(deviceId))
deviceId,
message: args[0] ECCrypto.encrypt(devicePub, Buffer.from(args[0], 'utf-8')).then(
}).then(encryptedMessage => { encryptedMessage => {
args[0] = JSON.stringify(encryptedMessage) args[0] = JSON.stringify(encryptedMessage)
oldSend.apply(res, args) oldSend.apply(res, args)
}) }
)
} }
if (!authorized || process.env.SHOCK_ENCRYPTION_ECC === 'false') { if (!authorized || process.env.SHOCK_ENCRYPTION_ECC === 'false') {
@ -195,7 +184,7 @@ const server = program => {
await LightningServices.init() await LightningServices.init()
} }
await new Promise((resolve, reject) => { await /** @type {Promise<void>} */ (new Promise((resolve, reject) => {
LightningServices.services.lightning.getInfo({}, (err, res) => { LightningServices.services.lightning.getInfo({}, (err, res) => {
if ( if (
err && err &&
@ -207,9 +196,7 @@ const server = program => {
resolve() resolve()
} }
}) })
}) }))
const auth = require('../services/auth/auth')
app.use(compression()) app.use(compression())
@ -320,7 +307,7 @@ const server = program => {
return httpsServer return httpsServer
} }
const httpServer = Http.Server(app) const httpServer = new Http.Server(app)
return httpServer return httpServer
} catch (err) { } catch (err) {
logger.error(err.message) logger.error(err.message)
@ -328,7 +315,7 @@ const server = program => {
'An error has occurred while finding an LND cert to use to open an HTTPS server' 'An error has occurred while finding an LND cert to use to open an HTTPS server'
) )
logger.warn('Falling back to opening an HTTP server...') logger.warn('Falling back to opening an HTTP server...')
const httpServer = Http.Server(app) const httpServer = new Http.Server(app)
return httpServer return httpServer
} }
} }
@ -366,11 +353,13 @@ const server = program => {
}, },
Sockets, Sockets,
{ {
serverHost,
serverPort, serverPort,
useTLS: program.useTLS, useTLS: program.useTLS,
CA, CA,
CA_KEY CA_KEY,
runPrivateKey,
runPublicKey,
accessSecret
} }
) )
@ -408,12 +397,12 @@ const server = program => {
Storage.setItem('relay/url', noProtocolAddress) Storage.setItem('relay/url', noProtocolAddress)
]) ])
const dataToQr = JSON.stringify({ const dataToQr = JSON.stringify({
internalIP: `${params.relayId}@${noProtocolAddress}`, URI: `https://${params.relayId}@${noProtocolAddress}`,
walletPort: 443, // Null-check is just to please typescript
externalIP: `${params.relayId}@${noProtocolAddress}` accessSecret: accessSecret && accessSecret.toString('base64')
}) })
qrcode.generate(dataToQr, { small: true }) qrcode.generate(dataToQr, { small: false })
logger.info(`connect to ${params.relayId}@${noProtocolAddress}`) logger.info(`connect to ${params.relayId}@${noProtocolAddress}:443`)
} else { } else {
logger.error('!! Relay did not connect to server !!') logger.error('!! Relay did not connect to server !!')
} }
@ -436,6 +425,7 @@ const server = program => {
} }
serverInstance.listen(serverPort, serverHost) serverInstance.listen(serverPort, serverHost)
logger.info('App listening on ' + serverHost + ' port ' + serverPort) logger.info('App listening on ' + serverHost + ' port ' + serverPort)
// @ts-expect-error
module.server = serverInstance module.server = serverInstance
} catch (err) { } catch (err) {
logger.error({ exception: err, message: err.message, code: err.code }) logger.error({ exception: err, message: err.message, code: err.code })

View file

@ -1 +1,8 @@
/**
* @format
*/
//@ts-check
module.exports = require('./ECC') module.exports = require('./ECC')
module.exports.convertToEncryptedMessage = require('./crypto').convertToEncryptedMessage

View file

@ -134,15 +134,15 @@ export interface Services {
} }
export interface ListChannelsReq { export interface ListChannelsReq {
active_only: boolean active_only?: boolean
inactive_only: boolean inactive_only?: boolean
public_only: boolean public_only?: boolean
private_only: boolean private_only?: boolean
/** /**
* Filters the response for channels with a target peer's pubkey. If peer is * Filters the response for channels with a target peer's pubkey. If peer is
* empty, all channels will be returned. * empty, all channels will be returned.
*/ */
peer: Common.Bytes peer?: Common.Bytes
} }
/** /**
@ -193,4 +193,8 @@ export interface AddInvoiceRes {
* all payments for this invoice as we require it for end to end security. * all payments for this invoice as we require it for end to end security.
*/ */
payment_addr: Common.Bytes payment_addr: Common.Bytes
/**
* Custom property, by us.
*/
liquidityCheck?: boolean
} }