diff --git a/lib/new-admin/admin-server.js b/lib/new-admin/admin-server.js index 60e36eb9..cbc85541 100644 --- a/lib/new-admin/admin-server.js +++ b/lib/new-admin/admin-server.js @@ -71,7 +71,7 @@ app.get('/api/register', (req, res, next) => { if (!otp) return next() - return login.register(otp) + return login.register(req) .then(r => { if (r.expired) return res.status(401).send('OTP expired, generate new registration link') diff --git a/lib/new-admin/graphql/schema.js b/lib/new-admin/graphql/schema.js index db678330..cb1a9e2b 100644 --- a/lib/new-admin/graphql/schema.js +++ b/lib/new-admin/graphql/schema.js @@ -224,7 +224,7 @@ const typeDefs = gql` transactionsCsv(from: Date, until: Date, limit: Int, offset: Int): String accounts: JSONObject config: JSONObject - userTokens: [UserToken] + userTokens(browser: String!, os: String!): [UserToken] } enum MachineAction { @@ -283,7 +283,7 @@ const resolvers = { transactions.batch(from, until, limit, offset).then(parseAsync), config: () => settingsLoader.loadLatestConfigOrNone(), accounts: () => settingsLoader.loadAccounts(), - userTokens: () => tokenManager.getTokenList() + userTokens: (...[, { browser, os }]) => tokenManager.getTokenList(browser, os) }, Mutation: { machineAction: (...[, { deviceId, action, cassette1, cassette2, newName }]) => machineAction({ deviceId, action, cassette1, cassette2, newName }), diff --git a/lib/new-admin/login.js b/lib/new-admin/login.js index 0eaaff21..278c4714 100644 --- a/lib/new-admin/login.js +++ b/lib/new-admin/login.js @@ -1,5 +1,6 @@ const crypto = require('crypto') +const browserOS = require('../../new-lamassu-admin/src/utils/browser-os') const db = require('../db') function generateOTP (name) { @@ -21,15 +22,18 @@ function validateOTP (otp) { .catch(() => ({ success: false, expired: false })) } -function register (otp) { +function register (req) { + const otp = req.query.otp + return validateOTP(otp) .then(r => { if (!r.success) return r + const deviceInfo = browserOS.getInformation(req.headers['user-agent']) const token = crypto.randomBytes(32).toString('hex') - const sql = 'insert into user_tokens (token, name) values ($1, $2)' + const sql = 'insert into user_tokens (token, name, browser_version, os_version, ip_address) values ($1, $2, $3, $4, $5)' - return db.none(sql, [token, r.name]) + return db.none(sql, [token, r.name, deviceInfo.browser, deviceInfo.OS, browserOS.getRequestIP(req)]) .then(() => ({ success: true, token: token })) }) .catch(() => ({ success: false, expired: false })) diff --git a/lib/token-manager.js b/lib/token-manager.js index 3c9a7cc5..25e52b88 100644 --- a/lib/token-manager.js +++ b/lib/token-manager.js @@ -1,8 +1,8 @@ const db = require('./db') -function getTokenList () { - const sql = `select * from user_tokens` - return db.any(sql) +function getTokenList (browser, os) { + const sql = `select * from user_tokens where browser_version=$1 and os_version=$2` + return db.any(sql, [browser, os]) } function revokeToken (token) { @@ -10,4 +10,4 @@ function revokeToken (token) { return db.none(sql, [token]) } -module.exports = { getTokenList, revokeToken } \ No newline at end of file +module.exports = { getTokenList, revokeToken } diff --git a/migrations/1603438527057-add-browser-os-info.js b/migrations/1603438527057-add-browser-os-info.js new file mode 100644 index 00000000..e0e5e613 --- /dev/null +++ b/migrations/1603438527057-add-browser-os-info.js @@ -0,0 +1,15 @@ +const db = require('./db') + +exports.up = function (next) { + var sql = [ + 'ALTER TABLE user_tokens ADD COLUMN browser_version text', + 'ALTER TABLE user_tokens ADD COLUMN os_version text', + 'ALTER TABLE user_tokens ADD COLUMN ip_address inet', + ] + + db.multi(sql, next) +} + +exports.down = function (next) { + next() +} diff --git a/new-lamassu-admin/src/pages/TokenManagement/TokenManagement.js b/new-lamassu-admin/src/pages/TokenManagement/TokenManagement.js index c503a547..57aad2a4 100644 --- a/new-lamassu-admin/src/pages/TokenManagement/TokenManagement.js +++ b/new-lamassu-admin/src/pages/TokenManagement/TokenManagement.js @@ -9,14 +9,15 @@ import Title from 'src/components/Title' import { IconButton } from 'src/components/buttons' import DataTable from 'src/components/tables/DataTable' import { ReactComponent as DeleteIcon } from 'src/styling/icons/action/delete/enabled.svg' +import * as browserOS from 'src/utils/browser-os' import { mainStyles } from './TokenManagement.styles' const useStyles = makeStyles(mainStyles) const GET_USER_TOKENS = gql` - query userTokens { - userTokens { + query userTokens($browser: String!, $os: String!) { + userTokens(browser: $browser, os: $os) { token name created @@ -35,11 +36,16 @@ const REVOKE_USER_TOKEN = gql` const Tokens = () => { const classes = useStyles() - const { data: tknResponse } = useQuery(GET_USER_TOKENS) + const userAgent = browserOS.getInformation(navigator.userAgent) + + const { data: tknResponse } = useQuery(GET_USER_TOKENS, { + variables: { + browser: `${userAgent.browser}`, + os: `${userAgent.OS}` + } + }) const [revokeToken] = useMutation(REVOKE_USER_TOKEN, { - onCompleted: () => console.log('passed'), - onError: () => console.log('failed'), refetchQueries: () => ['userTokens'] }) diff --git a/new-lamassu-admin/src/utils/browser-os.js b/new-lamassu-admin/src/utils/browser-os.js new file mode 100644 index 00000000..13bef62e --- /dev/null +++ b/new-lamassu-admin/src/utils/browser-os.js @@ -0,0 +1,14 @@ +const parser = require('ua-parser-js') + +function getRequestIP(req) { + return req.ip +} + +function getInformation(uaString) { + const userAgent = parser(uaString) + const browser = `${userAgent.browser.name} ${userAgent.browser.version}` + const OS = `${userAgent.os.name} ${userAgent.os.version}` + return { browser: browser, OS: OS } +} + +module.exports = { getRequestIP, getInformation } diff --git a/package-lock.json b/package-lock.json index 699052b0..233ba9ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10541,6 +10541,11 @@ "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" }, + "ua-parser-js": { + "version": "0.7.22", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz", + "integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q==" + }, "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", @@ -10795,7 +10800,7 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.20.7.tgz", "integrity": "sha512-VU6/DSUX93d1fCzBz7WP/SGCQizO1rKZi4Px9j/3yRyfssHyFcZamMw2/sj4E8TlfMXONvZLoforR8B4bRoyTQ==", "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git", + "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2-cookies": "^1.1.0", diff --git a/package.json b/package.json index 31b53418..9fb7380f 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "socket.io-client": "^2.0.3", "talisman": "^0.20.0", "twilio": "^3.6.1", + "ua-parser-js": "^0.7.22", "uuid": "^3.1.0", "web3": "^0.20.6", "winston": "^2.4.2",