From ccdf8971bbc5e46c353a2edf282ac59dc0217cde Mon Sep 17 00:00:00 2001 From: Carlo Venusino Date: Wed, 7 Jul 2021 09:19:23 +0200 Subject: [PATCH] TT#122015 Add QR-Code to login to sip:phone mobile app from CSC - TT#128156 Add QR-Code button to the header - TT#128157 Add QR-Code render library - TT#128158 Implement QR-Code generation - TT#129205 Render QR-Code in the popup - TT#129224 Create store test and api test (including endpoint mockup) NOTE You need to enable sip_phone.show_qr_csc in /etc/ngcp-config/config.yml of your environment to be able to see the QR code icon Change-Id: Ifa065ef057549696387026c5a62cf0f5297ffb05 (cherry picked from commit 389a6bcb9d42ecd9131ccd1f4570deed9c24f78a) --- env/Dockerfile | 2 +- package.json | 1 + src/api/user.js | 12 ++++++ src/components/CscDialogQrCode.vue | 56 ++++++++++++++++++++++++++ src/helpers/qr.js | 3 ++ src/i18n/en.json | 5 +++ src/layouts/CscLayoutMain.vue | 26 +++++++++++- src/store/user.js | 33 ++++++++++++++- t/Dockerfile | 2 +- test/jest/__tests__/api/user.spec.js | 25 ++++++++++++ test/jest/__tests__/helpers/qr.spec.js | 22 ++++++++++ test/jest/__tests__/store/user.spec.js | 8 ++++ yarn.lock | 47 +++++++++++++++++++-- 13 files changed, 233 insertions(+), 9 deletions(-) create mode 100644 src/components/CscDialogQrCode.vue create mode 100644 src/helpers/qr.js create mode 100644 test/jest/__tests__/api/user.spec.js create mode 100644 test/jest/__tests__/helpers/qr.spec.js diff --git a/env/Dockerfile b/env/Dockerfile index 47876591..717c5978 100644 --- a/env/Dockerfile +++ b/env/Dockerfile @@ -5,7 +5,7 @@ FROM docker.mgm.sipwise.com/sipwise-buster:latest # is updated with the current date. It will force refresh of all # of the base images and things like `apt-get update` won't be using # old cached versions when the Dockerfile is built. -ENV REFRESHED_AT 2020-08-27 +ENV REFRESHED_AT 2021-07-07 # files that get-code generates COPY env/sources.list.d/builddeps.list /etc/apt/sources.list.d/ diff --git a/package.json b/package.json index ddbfe1b5..0ca9df2f 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "load-script": "^1.0.0", "lodash": "4.17.21", "moment": "^2.27.0", + "qrcode": "1.4.4", "quasar": "^1.15.2", "vue-i18n": "^8.0.0", "vue-password-strength-meter": "^1.7.2", diff --git a/src/api/user.js b/src/api/user.js index 3ad73f17..be8e3c21 100644 --- a/src/api/user.js +++ b/src/api/user.js @@ -3,6 +3,7 @@ import _ from 'lodash' import Vue from 'vue' import { get, + post, getList, patchReplace } from './common' @@ -135,3 +136,14 @@ export async function getResellerBranding () { resource: 'resellerbrandings' }) } + +export async function createAuthToken (tokenExpiringTime) { + const response = await post({ + resource: 'authtokens', + body: { + type: 'onetime', + expires: tokenExpiringTime + } + }) + return response.token +} diff --git a/src/components/CscDialogQrCode.vue b/src/components/CscDialogQrCode.vue new file mode 100644 index 00000000..d2e1c9f3 --- /dev/null +++ b/src/components/CscDialogQrCode.vue @@ -0,0 +1,56 @@ + + + diff --git a/src/helpers/qr.js b/src/helpers/qr.js new file mode 100644 index 00000000..a0f995f8 --- /dev/null +++ b/src/helpers/qr.js @@ -0,0 +1,3 @@ +export function qrPayload ({ subscriber, server, token }) { + return `username=${subscriber}&server=${server}&token=${token}` +} diff --git a/src/i18n/en.json b/src/i18n/en.json index 956f4960..fbb13bdf 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -385,6 +385,7 @@ "PBX Settings": "PBX Settings", "PIN": "PIN", "Page Header": "Page Header", + "Page not found": "Page not found", "Parallel Ringing": "Parallel Ringing", "Password": "Password", "Password Retype": "Password Retype", @@ -412,6 +413,7 @@ "Privacy": "Privacy", "Private": "Private", "Q-Value": "Q-Value", + "QR code unavailable. Please retry later": "QR code unavailable. Please retry later", "Quality": "Quality", "Queue Length": "Queue Length", "Random Ringing": "Random Ringing", @@ -469,6 +471,7 @@ "Renew Notify Email": "Renew Notify Email", "Reset": "Reset", "Reset Filters": "Reset Filters", + "Reset Password": "Reset Password", "Reset filters": "Reset filters", "Reset greeting sound": "Reset greeting sound", "Reset of timesets completed": "Reset of timesets completed", @@ -484,6 +487,8 @@ "Saturday": "Saturday", "Save": "Save", "Save new password": "Save new password", + "Scan QR code": "Scan QR code", + "Scan to login sip:phone": "Scan to login sip:phone", "Screen Share": "Screen Share", "Search": "Search", "Seat": "Seat", diff --git a/src/layouts/CscLayoutMain.vue b/src/layouts/CscLayoutMain.vue index 1909d889..2eab6f88 100644 --- a/src/layouts/CscLayoutMain.vue +++ b/src/layouts/CscLayoutMain.vue @@ -70,6 +70,15 @@ /> + { + beforeEach( () => { + Vue.http.interceptors = [] + }) + it('should fetch an authtoken', async () => { + const authToken = 'd73ddf3a-0bf3-47bd-bee9-13bd972b37ec' + Vue.http.interceptors.unshift((request, next) => { + next(request.respondWith(JSON.stringify({ + token: authToken + }), { + status: 201 + })) + }) + const response = await createAuthToken(300) + expect(response).toEqual(authToken) + }) +}) diff --git a/test/jest/__tests__/helpers/qr.spec.js b/test/jest/__tests__/helpers/qr.spec.js new file mode 100644 index 00000000..05a0f124 --- /dev/null +++ b/test/jest/__tests__/helpers/qr.spec.js @@ -0,0 +1,22 @@ +/* eslint-disable */ + +import { + qrPayload +} from 'src/helpers/qr' + +describe('QR helpers', function () { + + it('checks the format of QR payload', () => { + const subscriber = '43991002' + const server = 'sipwise.com' + const token = 'e7cd5253-79fc-4aec-bb1b-4b86eff96c7d' + const payload = `username=${subscriber}&server=${server}&token=${token}` + const result = qrPayload({ + subscriber: subscriber, + server: server, + token: token + }) + expect(result).toBe(payload) + }) + +}) diff --git a/test/jest/__tests__/store/user.spec.js b/test/jest/__tests__/store/user.spec.js index 01fbe396..d40cfb61 100644 --- a/test/jest/__tests__/store/user.spec.js +++ b/test/jest/__tests__/store/user.spec.js @@ -24,4 +24,12 @@ describe('UserStore', () => { expect(state.jwt).toBe('1234') expect(state.subscriberId).toBe('5678') }) + + it('should successfully store a qrcode ',() => { + const dataImg = 'data:image;123456789' + const state = {} + UserStore.mutations.setQrCode(state, dataImg) + expect(state.qrCode).toBe(dataImg) + }) + }) diff --git a/yarn.lock b/yarn.lock index 8308bc74..5ae065c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2488,7 +2488,7 @@ base64-js@^1.0.2: resolved "https://npm-registry.sipwise.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== -base64-js@^1.5.1: +base64-js@^1.3.1, base64-js@^1.5.1: version "1.5.1" resolved "https://npm-registry.sipwise.com/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -2788,7 +2788,7 @@ buffer-fill@^1.0.0: resolved "https://npm-registry.sipwise.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= -buffer-from@^1.0.0: +buffer-from@^1.0.0, buffer-from@^1.1.1: version "1.1.1" resolved "https://npm-registry.sipwise.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== @@ -2820,6 +2820,14 @@ buffer@^5.1.0, buffer@^5.2.1, buffer@^5.5.0: base64-js "^1.0.2" ieee754 "^1.1.4" +buffer@^5.4.3: + version "5.7.1" + resolved "https://npm-registry.sipwise.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://npm-registry.sipwise.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" @@ -4221,6 +4229,11 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dijkstrajs@^1.0.1: + version "1.0.2" + resolved "https://npm-registry.sipwise.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257" + integrity sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg== + dir-glob@^3.0.1: version "3.0.1" resolved "https://npm-registry.sipwise.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -6106,6 +6119,11 @@ icss-utils@^4.0.0, icss-utils@^4.1.1: dependencies: postcss "^7.0.14" +ieee754@^1.1.13: + version "1.2.1" + resolved "https://npm-registry.sipwise.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ieee754@^1.1.4: version "1.1.13" resolved "https://npm-registry.sipwise.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" @@ -6675,6 +6693,11 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: resolved "https://npm-registry.sipwise.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +isarray@^2.0.1: + version "2.0.5" + resolved "https://npm-registry.sipwise.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isbinaryfile@4.0.6: version "4.0.6" resolved "https://npm-registry.sipwise.com/isbinaryfile/-/isbinaryfile-4.0.6.tgz#edcb62b224e2b4710830b67498c8e4e5a4d2610b" @@ -9004,6 +9027,11 @@ pn@^1.1.0: resolved "https://npm-registry.sipwise.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== +pngjs@^3.3.0: + version "3.4.0" + resolved "https://npm-registry.sipwise.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" + integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== + portfinder@^1.0.26: version "1.0.28" resolved "https://npm-registry.sipwise.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" @@ -9550,6 +9578,19 @@ q@^1.1.2: resolved "https://npm-registry.sipwise.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qrcode@1.4.4: + version "1.4.4" + resolved "https://npm-registry.sipwise.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83" + integrity sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q== + dependencies: + buffer "^5.4.3" + buffer-alloc "^1.2.0" + buffer-from "^1.1.1" + dijkstrajs "^1.0.1" + isarray "^2.0.1" + pngjs "^3.3.0" + yargs "^13.2.4" + qs@6.7.0: version "6.7.0" resolved "https://npm-registry.sipwise.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" @@ -12410,7 +12451,7 @@ yargs@^12.0.5: y18n "^3.2.1 || ^4.0.0" yargs-parser "^11.1.1" -yargs@^13.3.0, yargs@^13.3.2: +yargs@^13.2.4, yargs@^13.3.0, yargs@^13.3.2: version "13.3.2" resolved "https://npm-registry.sipwise.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==