Skip to content
Snippets Groups Projects

Implement request signing and permitted domains

Merged Gospodin Bodurov requested to merge iframe-security into master
Files
4
@@ -47,6 +47,7 @@ import {
@@ -47,6 +47,7 @@ import {
checkRecoveryKeyCombine,
checkRecoveryKeyCombine,
encryptShare
encryptShare
} from "../utilities/secrets";
} from "../utilities/secrets";
 
import { generateNonce, signRSA } from "../utilities/cryptoUtils";
const penpalMethods = require("../../temp/penpal-methods").default;
const penpalMethods = require("../../temp/penpal-methods").default;
const WopiAPI = require("./wopiapi-iframe");
const WopiAPI = require("./wopiapi-iframe");
@@ -129,6 +130,24 @@ function setIdentityInLocalStorage(identityToStore, extendKey = true) {
@@ -129,6 +130,24 @@ function setIdentityInLocalStorage(identityToStore, extendKey = true) {
);
);
}
}
 
async function setCurrentlyLoadedIdentity(identity) {
 
if (identity) {
 
let nonce = window.viamApi.getNonce();
 
 
if (!nonce) {
 
nonce = generateNonce();
 
const privateKey = identity.authentication.privateKey;
 
const nonceSignature = await signRSA(privateKey, nonce);
 
window.viamApi.setNonce(Buffer.from(nonce).toString("base64"));
 
window.viamApi.setNonceSignature(
 
Buffer.from(nonceSignature).toString("base64")
 
);
 
}
 
}
 
 
window.currentlyLoadedIdentity = identity;
 
}
 
function getProfileData(identity) {
function getProfileData(identity) {
return new Penpal.Promise(executeResultUpper => {
return new Penpal.Promise(executeResultUpper => {
executeRestfulFunction(
executeRestfulFunction(
@@ -260,7 +279,7 @@ const destroyIdentity = () => {
@@ -260,7 +279,7 @@ const destroyIdentity = () => {
const { publicKey } = window.currentlyLoadedIdentity.authentication;
const { publicKey } = window.currentlyLoadedIdentity.authentication;
delete window.loadedIdentities[publicKey];
delete window.loadedIdentities[publicKey];
window.currentlyLoadedIdentity = null;
setCurrentlyLoadedIdentity(null);
destroyIdentityFromLocalStorage(publicKey);
destroyIdentityFromLocalStorage(publicKey);
}
}
};
};
@@ -382,6 +401,7 @@ function loadIdentityInternal(identityKey, pinCode) {
@@ -382,6 +401,7 @@ function loadIdentityInternal(identityKey, pinCode) {
return new Penpal.Promise(result => {
return new Penpal.Promise(result => {
getIdentityFromLocalStorage(identityKey, pinCode)
getIdentityFromLocalStorage(identityKey, pinCode)
.then(async loadedIdentity => {
.then(async loadedIdentity => {
 
console.log({ loadedIdentity });
if (loadedIdentity == null) {
if (loadedIdentity == null) {
result({
result({
data: "",
data: "",
@@ -390,10 +410,17 @@ function loadIdentityInternal(identityKey, pinCode) {
@@ -390,10 +410,17 @@ function loadIdentityInternal(identityKey, pinCode) {
"Please restore or authorize your account via another device."
"Please restore or authorize your account via another device."
});
});
}
}
 
if (!loadedIdentity.privateKey) {
 
result({
 
data: "",
 
code: "400",
 
status: "No privateKey"
 
});
 
}
localStorage.removeItem("attempt");
localStorage.removeItem("attempt");
window.loadedIdentities[identityKey] = loadedIdentity;
window.loadedIdentities[identityKey] = loadedIdentity;
window.currentlyLoadedIdentity = loadedIdentity;
await setCurrentlyLoadedIdentity(loadedIdentity);
if (identityKey === localStorage.getItem("authenticatedIdentity")) {
if (identityKey === localStorage.getItem("authenticatedIdentity")) {
window.currentlyAuthenticatedIdentity = loadedIdentity;
window.currentlyAuthenticatedIdentity = loadedIdentity;
@@ -479,10 +506,10 @@ function getCertificateForPassport(passportUUID, internal) {
@@ -479,10 +506,10 @@ function getCertificateForPassport(passportUUID, internal) {
getProfileData(passportIdentity).then(executeResult1 => {
getProfileData(passportIdentity).then(executeResult1 => {
setIdentityInLocalStorage(passportIdentity)
setIdentityInLocalStorage(passportIdentity)
.then(() => {
.then(async () => {
window.currentlyAuthenticatedIdentity = passportIdentity;
window.currentlyAuthenticatedIdentity = passportIdentity;
window.lastTimeGetProfile = 0;
window.lastTimeGetProfile = 0;
window.currentlyLoadedIdentity = passportIdentity;
await setCurrentlyLoadedIdentity(passportIdentity);
const copyOfCryptoData = JSON.parse(
const copyOfCryptoData = JSON.parse(
JSON.stringify(cryptoData)
JSON.stringify(cryptoData)
);
);
@@ -529,7 +556,7 @@ function getCertificateForPassport(passportUUID, internal) {
@@ -529,7 +556,7 @@ function getCertificateForPassport(passportUUID, internal) {
const connection = Penpal.connectToParent({
const connection = Penpal.connectToParent({
// Methods child is exposing to parent
// Methods child is exposing to parent
methods: {
methods: {
initialize: (apiUrl, wopiUrl, collaboraUrl) => {
initialize: async (apiUrl, wopiUrl, collaboraUrl) => {
if (!apiUrl) {
if (!apiUrl) {
apiUrl = `${window.location.origin}/api/`;
apiUrl = `${window.location.origin}/api/`;
console.warn(`API host URL not specified. Fall back to ${apiUrl}`); // eslint-disable-line no-console
console.warn(`API host URL not specified. Fall back to ${apiUrl}`); // eslint-disable-line no-console
@@ -555,11 +582,40 @@ const connection = Penpal.connectToParent({
@@ -555,11 +582,40 @@ const connection = Penpal.connectToParent({
collaboraUrl.charAt(collaboraUrl.length - 1) === "/"
collaboraUrl.charAt(collaboraUrl.length - 1) === "/"
? collaboraUrl
? collaboraUrl
: collaboraUrl + "/";
: collaboraUrl + "/";
 
 
const {
 
code,
 
data: { domains: permittedDomains }
 
} = await penpalMethods.identityGetPermittedDomains();
 
 
if (code !== "200") {
 
throw new Error("Unable to retrieve a list of permitted domains.");
 
}
 
 
const iframeOrigin = document.referrer;
 
if (
 
iframeOrigin && // Empty iframe origins are allowed. This is the case for Roundcube plugin
 
permittedDomains &&
 
permittedDomains.length
 
) {
 
let iframeOriginIsPermitted = false;
 
 
for (const domain of permittedDomains) {
 
if (iframeOrigin.includes(domain)) {
 
iframeOriginIsPermitted = true;
 
break;
 
}
 
}
 
 
if (!iframeOriginIsPermitted) {
 
throw new Error(`Iframe origin "${iframeOrigin}" is not permitted.`);
 
}
 
}
},
},
...penpalMethods,
...penpalMethods,
createIdentity(pinCode) {
createIdentity(pinCode) {
return new Penpal.Promise(result => {
return new Penpal.Promise(result => {
createPassportCertificate(makeid()).then(function (keys) {
createPassportCertificate(makeid()).then(async function (keys) {
const newIdentity = new Identity();
const newIdentity = new Identity();
const cryptoData = new CryptoData();
const cryptoData = new CryptoData();
cryptoData.setPublicKey(keys["publicKeyPEM"]);
cryptoData.setPublicKey(keys["publicKeyPEM"]);
@@ -568,7 +624,7 @@ const connection = Penpal.connectToParent({
@@ -568,7 +624,7 @@ const connection = Penpal.connectToParent({
newIdentity.setAuthentication(cryptoData);
newIdentity.setAuthentication(cryptoData);
newIdentity.setPinCode(pinCode);
newIdentity.setPinCode(pinCode);
window.currentlyLoadedIdentity = newIdentity;
await setCurrentlyLoadedIdentity(newIdentity);
localStorage.setItem(
localStorage.setItem(
"currentlyLoadedIdentity",
"currentlyLoadedIdentity",
JSON.stringify(newIdentity)
JSON.stringify(newIdentity)
@@ -629,7 +685,7 @@ const connection = Penpal.connectToParent({
@@ -629,7 +685,7 @@ const connection = Penpal.connectToParent({
identity.pinCode = newPinCode;
identity.pinCode = newPinCode;
await setIdentityInLocalStorage(identity);
await setIdentityInLocalStorage(identity);
window.currentlyAuthenticatedIdentity = identity;
window.currentlyAuthenticatedIdentity = identity;
window.currentlyLoadedIdentity = identity;
await setCurrentlyLoadedIdentity(identity);
return encodeResponse("200", null, "Successfully changed pincode");
return encodeResponse("200", null, "Successfully changed pincode");
} else {
} else {
@@ -758,7 +814,7 @@ const connection = Penpal.connectToParent({
@@ -758,7 +814,7 @@ const connection = Penpal.connectToParent({
let sequence = Promise.resolve();
let sequence = Promise.resolve();
if (executeResult.code === "200") {
if (executeResult.code === "200") {
sequence = sequence.then(() => {
sequence = sequence.then(() => {
setIdentityInLocalStorage(registerIdentity);
setIdentityInLocalStorage(window.currentlyLoadedIdentity);
});
});
}
}
sequence
sequence
@@ -791,6 +847,7 @@ const connection = Penpal.connectToParent({
@@ -791,6 +847,7 @@ const connection = Penpal.connectToParent({
});
});
},
},
login: async (loginIdentity, mode, requestCode, requestActionID) => {
login: async (loginIdentity, mode, requestCode, requestActionID) => {
 
const localStorageIdentity = getIdentityFromLocalStorage();
if (!window.loadedIdentities[loginIdentity.authentication.publicKey]) {
if (!window.loadedIdentities[loginIdentity.authentication.publicKey]) {
return {
return {
data: "",
data: "",
@@ -995,7 +1052,7 @@ const connection = Penpal.connectToParent({
@@ -995,7 +1052,7 @@ const connection = Penpal.connectToParent({
"currentlyLoadedIdentity"
"currentlyLoadedIdentity"
);
);
const identity = new Identity(currentlyLoadedIdentity);
const identity = new Identity(currentlyLoadedIdentity);
window.currentlyLoadedIdentity = identity;
await setCurrentlyLoadedIdentity(identity);
const { publicKey } = identity.authentication;
const { publicKey } = identity.authentication;
window.loadedIdentities[publicKey] = identity;
window.loadedIdentities[publicKey] = identity;
window.viamAnonymousApi.setIdentity(publicKey);
window.viamAnonymousApi.setIdentity(publicKey);
@@ -2489,7 +2546,7 @@ connection.promise.then(parent => {
@@ -2489,7 +2546,7 @@ connection.promise.then(parent => {
if (event.key === "authenticatedIdentity" && event.newValue === null) {
if (event.key === "authenticatedIdentity" && event.newValue === null) {
const publicKey =
const publicKey =
window.currentlyAuthenticatedIdentity.authentication.publicKey;
window.currentlyAuthenticatedIdentity.authentication.publicKey;
window.currentlyLoadedIdentity = null;
setCurrentlyLoadedIdentity(null);
window.currentlyAuthenticatedIdentity = null;
window.currentlyAuthenticatedIdentity = null;
const event = createEvent("LogoutFromAnotherTab", "Logout", [publicKey]);
const event = createEvent("LogoutFromAnotherTab", "Logout", [publicKey]);
parent.onEvent(event);
parent.onEvent(event);
@@ -2572,7 +2629,8 @@ connection.promise.then(parent => {
@@ -2572,7 +2629,8 @@ connection.promise.then(parent => {
false
false
);
);
window.currentlyLoadedIdentity = identity;
!window.currentlyLoadedIdentity &&
 
(await setCurrentlyLoadedIdentity(identity));
if (!identityAuthenticatedEvent && identity) {
if (!identityAuthenticatedEvent && identity) {
const event = createEvent("IdentityAuthenticated", "Authenticated", [
const event = createEvent("IdentityAuthenticated", "Authenticated", [
@@ -2604,7 +2662,7 @@ connection.promise.then(parent => {
@@ -2604,7 +2662,7 @@ connection.promise.then(parent => {
}
}
identityAuthenticatedEvent = false;
identityAuthenticatedEvent = false;
window.currentlyLoadedIdentity = null;
setCurrentlyLoadedIdentity(null);
}
}
localStorage.removeItem("currentlyLoadedIdentity");
localStorage.removeItem("currentlyLoadedIdentity");
@@ -2711,7 +2769,7 @@ connection.promise.then(parent => {
@@ -2711,7 +2769,7 @@ connection.promise.then(parent => {
localStorage.removeItem("token");
localStorage.removeItem("token");
localStorage.removeItem("authenticatedIdentity");
localStorage.removeItem("authenticatedIdentity");
delete window.loadedIdentities[authenticationPublicKey];
delete window.loadedIdentities[authenticationPublicKey];
window.currentlyLoadedIdentity = null;
setCurrentlyLoadedIdentity(null);
window.currentlyAuthenticatedIdentity = null;
window.currentlyAuthenticatedIdentity = null;
window.lastTimeGetProfile = 0;
window.lastTimeGetProfile = 0;
Loading