diff --git a/Gopkg.toml b/Gopkg.toml index 349b503370d11addf17bca0a46703d4e5aa98825..7e752095a137fa69907fe401e8baa8072079573a 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -25,7 +25,7 @@ # unused-packages = true [[constraint]] - branch = "master" + branch = "390-device-management-ability-to-remove-device" name = "code.vereign.com/code/restful-api" [prune] diff --git a/javascript/src/Identity.js b/javascript/src/Identity.js index 43a52eafc057f67cf2feb961db87e5392f015f4d..22b112ca9e833dd25ce67e38def5a22cf32bd2ef 100644 --- a/javascript/src/Identity.js +++ b/javascript/src/Identity.js @@ -1,51 +1,39 @@ -function Identity() { -} - -Identity.prototype.set = function(obj) { - for(var member in obj) { - this[member] = JSON.parse(JSON.stringify(obj[member])) +class Identity { + constructor(source) { + let identityData = {}; + + if (typeof source === "string") { + try { + identityData = JSON.parse(source); + } catch (e) { + console.warn(e); + } + } else if (typeof source === "object") { + identityData = source; + } + + const { authentication, pinCode, passports } = identityData; + + this.authentication = authentication; + this.pinCode = pinCode; + this.passports = passports || {}; } -}; - -Identity.prototype.serialize = function() { - return JSON.stringify(this) -}; - -Identity.prototype.deserialize = function(serialized) { - var obj = JSON.parse(serialized); - this.set(obj) -}; - -Identity.prototype.setAuthentication = function(cryptoData) { - this["authentication"] = cryptoData -}; - -Identity.prototype.getAuthentication = function() { - return this["authentication"] -}; -Identity.prototype.setPinCode = function(pinCode) { - this["pinCode"] = pinCode -}; - -Identity.prototype.getPinCode = function() { - return this["pinCode"] -}; - -Identity.prototype.setPassport = function(passportUUID, cryptoData) { - if(this["passports"] === undefined || this["passports"] === null) { - this["passports"] = {} + setAuthentication(cryptoData) { + this.authentication = cryptoData; } - this["passports"][passportUUID] = cryptoData -}; + setPinCode(pinCode) { + this.pinCode = pinCode; + } -Identity.prototype.getPassport = function(passportUUID) { - if(this["passports"] === undefined || this["passports"] === null) { - this["passports"] = {} + setPassport(passportUUID, cryptoData) { + this.passports[passportUUID] = cryptoData; } - return this["passports"][passportUUID] -}; + getPassport(passportUUID) { + return this.passports[passportUUID]; + } +} -export default Identity; \ No newline at end of file +export default Identity; diff --git a/javascript/src/constants/statuses.js b/javascript/src/constants/statuses.js new file mode 100644 index 0000000000000000000000000000000000000000..64fe340b5b9cbac714070c61ae1a3bceba23af3e --- /dev/null +++ b/javascript/src/constants/statuses.js @@ -0,0 +1 @@ +export const STATUS_DEVICE_REVOKED = "Device revoked"; diff --git a/javascript/src/iframe/viamapi-iframe.js b/javascript/src/iframe/viamapi-iframe.js index 3a6be2bdd6c49e5599e24ee157f744a2d2a22784..7e363315bc4206db21018877603467aae71b98d6 100644 --- a/javascript/src/iframe/viamapi-iframe.js +++ b/javascript/src/iframe/viamapi-iframe.js @@ -18,6 +18,7 @@ import { } from '../utilities/signingUtilities'; import CryptoData from '../CryptoData'; import Identity from '../Identity'; +import {STATUS_DEVICE_REVOKED} from '../constants/statuses'; const penpalMethods = require('../../temp/penpal-methods').default; const WopiAPI = require('./wopiapi-iframe'); @@ -116,32 +117,28 @@ function getProfileData(identity) { }); } -function getIdentityFromLocalStorage(key, pinCode, extendTtl = true) { +async function getIdentityFromLocalStorage(key, pinCode, extendTtl = true) { const encryptedIdentity = localStorage.getItem(key); - if (encryptedIdentity == null) { + + if (!encryptedIdentity) { console.log("No such identity for public key"); - return Promise.resolve(null) + return null; } - return decryptMessage(encryptedIdentity, pinCode).then((serializedIdentity) => { - var parsedIdentity = JSON.parse(serializedIdentity); - parsedIdentity["pinCode"] = ""; - - if(extendTtl === true) { - var success = extendPinCodeTtl(key, pinCode); - if (success === true) { - return parsedIdentity - } else { - console.log("Can not extend pincode ttl"); - return null - } - } else { - return parsedIdentity - } - }); -} + const serializedIdentity = await decryptMessage(encryptedIdentity, pinCode); + + const identity = new Identity(serializedIdentity); + if (extendTtl) { + const success = extendPinCodeTtl(key, pinCode); + if (!success) { + console.log("Can not extend pincode ttl"); + return null; + } + } + return identity; +} function extendPinCodeTtl(key, pinCode) { if(pinCode == null || pinCode === "") { @@ -197,6 +194,34 @@ function createEvent(actionId, type, payloads) { } } +const destroyAuthentication = () => { + const authenticationPublicKey = localStorage.getItem("authenticatedIdentity"); + + window.viamApi.setIdentity(""); + window.viamApi.setSessionData("", ""); + + clearPinCodeTtl(authenticationPublicKey); + + localStorage.removeItem("uuid"); + localStorage.removeItem("token"); + localStorage.removeItem("authenticatedIdentity"); + + window.currentlyAuthenticatedIdentity = null; + window.lastTimeGetProfile = 0; +}; + +const destroyIdentity = () => { + destroyAuthentication(); + + if (window.currentlyLoadedIdentity) { + const { publicKey } = window.currentlyLoadedIdentity.authentication; + + delete window.loadedIdentities[publicKey]; + window.currentlyLoadedIdentity = null; + destroyIdentityFromLocalStorage(publicKey); + } +}; + window.loadedIdentities = {}; window.wopiAPI = new WopiAPI(); window.collaboraApi = new CollaboraAPI(); @@ -206,6 +231,8 @@ window.currentlyAuthenticatedIdentity = null; window.currentlyLoadedIdentity = null; window.lastTimeGetProfile = 0; +let iframeParent = null; + const handleIdentityLogin = (identity, uuid, token) => { const { loadedIdentities, viamApi } = window; const { publicKey } = identity.authentication; @@ -223,10 +250,22 @@ function executeRestfulFunction(type, that, fn, config, ...args) { const { currentlyAuthenticatedIdentity, viamApi, currentlyLoadedIdentity } = window; return new Penpal.Promise(executeResult => { - fn.apply(that, [config, ...args]).then((response) => { + fn.apply(that, [config, ...args]).then(async (response) => { const identity = currentlyAuthenticatedIdentity || currentlyLoadedIdentity; - if (type === "private" && identity && response.data.code === "400" && response.data.status === "Bad session") { + const { code, status } = response.data; + + // Destroy local storage in case device was revoked + if (type === "private" && code === "401" && status === STATUS_DEVICE_REVOKED) { + destroyIdentity(); + + const event = createEvent("", "DeviceRevoked"); + iframeParent.onEvent(event); + + return executeResult(response.data); + } + + if (type === "private" && identity && code === "400" && status === "Bad session") { viamApi.identityLogin(null, "previousaddeddevice") .then((response) => { if (response.data.code === "200") { @@ -259,11 +298,12 @@ function loadIdentityInternal(identityKey, pinCode) { }); } localStorage.removeItem("attempt"); - const copiedIdentity = JSON.parse(JSON.stringify(loadedIdentity)); + window.loadedIdentities[identityKey] = loadedIdentity; + window.currentlyLoadedIdentity = loadedIdentity; if (identityKey === localStorage.getItem("authenticatedIdentity")) { - window.currentlyAuthenticatedIdentity = copiedIdentity; + window.currentlyAuthenticatedIdentity = loadedIdentity; const uuid = localStorage.getItem("uuid"); const token = localStorage.getItem("token"); const deviceHash = await createDeviceHash(identityKey); @@ -272,14 +312,17 @@ function loadIdentityInternal(identityKey, pinCode) { window.viamApi.setSessionData(uuid, token); } - window.currentlyLoadedIdentity = copiedIdentity; window.viamAnonymousApi.setIdentity(window.currentlyLoadedIdentity.authentication.publicKey); - copiedIdentity.pinCode = ""; - copiedIdentity.authentication.privateKey = ""; + const { publicKey, x509Certificate } = loadedIdentity.authentication; result({ - "data": copiedIdentity, + "data": { + authentication: { + publicKey, + x509Certificate + } + }, "code": "200", "status": "Identity loaded" }); @@ -333,8 +376,7 @@ function getCertificateForPassport(passportUUID, internal) { } } - var passportIdentity = new Identity(); - passportIdentity.set(window.currentlyAuthenticatedIdentity); + const passportIdentity = window.currentlyAuthenticatedIdentity; var passport = passportIdentity.getPassport(passportUUID); if(passport === undefined || passport === null) { createPassportCertificate(passportUUID).then(function(keys){ @@ -699,17 +741,7 @@ const connection = Penpal.connectToParent({ null ); - window.viamApi.setIdentity(""); - window.viamApi.setSessionData("", ""); - clearPinCodeTtl(authenticationPublicKey); - - localStorage.removeItem("uuid"); - localStorage.removeItem("token"); - localStorage.removeItem("authenticatedIdentity"); - delete window.loadedIdentities[authenticationPublicKey]; - window.currentlyLoadedIdentity = null; - window.currentlyAuthenticatedIdentity = null; - window.lastTimeGetProfile = 0; + destroyAuthentication(); return identityLogoutResponse; }, @@ -1008,12 +1040,18 @@ const connection = Penpal.connectToParent({ }); }, getCurrentlyAuthenticatedIdentity() { - return new Penpal.Promise(result => { - result({"data" : window.currentlyAuthenticatedIdentity, - "code" : "200", - "status" : "Currently authenticated identity" - }) - }); + const { publicKey, x509Certificate } = window.currentlyAuthenticatedIdentity.authentication; + + return encodeResponse( + "200", + { + authentication: { + publicKey, + x509Certificate + } + }, + "Currently authenticated identity" + ); }, stringToUtf8ByteArray(str) { if (typeof str !== 'string') { @@ -1115,6 +1153,8 @@ const connection = Penpal.connectToParent({ }); connection.promise.then(parent => { + iframeParent = parent; + if (!navigator.cookieEnabled) { console.warn("Cookie disabled. Can't start library."); return;