mirror of https://github.com/keeweb/keeweb.git
distinct redirect URIs for storage providers
This commit is contained in:
parent
d3ebcabec4
commit
ec292705b3
20
Gruntfile.js
20
Gruntfile.js
|
@ -61,14 +61,11 @@ module.exports = function(grunt) {
|
|||
dest: 'tmp/index.html',
|
||||
nonull: true
|
||||
},
|
||||
'html-dist': {
|
||||
src: 'tmp/app.html',
|
||||
dest: 'dist/index.html',
|
||||
nonull: true
|
||||
},
|
||||
'404-dist': {
|
||||
src: 'app/404.html',
|
||||
dest: 'dist/404.html',
|
||||
'content-dist': {
|
||||
cwd: 'app/content/',
|
||||
src: '**',
|
||||
dest: 'dist/',
|
||||
expand: true,
|
||||
nonull: true
|
||||
},
|
||||
favicon: {
|
||||
|
@ -194,7 +191,7 @@ module.exports = function(grunt) {
|
|||
},
|
||||
app: {
|
||||
src: 'tmp/app.html',
|
||||
dest: 'tmp/app.html'
|
||||
dest: 'dist/app.html'
|
||||
}
|
||||
},
|
||||
htmlmin: {
|
||||
|
@ -270,7 +267,10 @@ module.exports = function(grunt) {
|
|||
sha: 'dev'
|
||||
}),
|
||||
publicPath: '/',
|
||||
contentBase: path.resolve(__dirname, 'tmp'),
|
||||
contentBase: [
|
||||
path.resolve(__dirname, 'tmp'),
|
||||
path.resolve(__dirname, 'app/content')
|
||||
],
|
||||
progress: false
|
||||
},
|
||||
js: {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>KeeWeb</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
window.opener.postMessage(
|
||||
{ storage: 'dropbox', search: location.search },
|
||||
window.location.origin
|
||||
);
|
||||
window.close();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>KeeWeb</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
window.opener.postMessage(
|
||||
{ storage: 'gdrive', search: location.search },
|
||||
window.location.origin
|
||||
);
|
||||
window.close();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>KeeWeb</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
window.opener.postMessage(
|
||||
{ storage: 'onedrive', search: location.search },
|
||||
window.location.origin
|
||||
);
|
||||
window.close();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -5,7 +5,6 @@ import { AppRightsChecker } from 'comp/app/app-rights-checker';
|
|||
import { ExportApi } from 'comp/app/export-api';
|
||||
import { SingleInstanceChecker } from 'comp/app/single-instance-checker';
|
||||
import { Updater } from 'comp/app/updater';
|
||||
import { AuthReceiver } from 'comp/browser/auth-receiver';
|
||||
import { FeatureTester } from 'comp/browser/feature-tester';
|
||||
import { FocusDetector } from 'comp/browser/focus-detector';
|
||||
import { IdleTracker } from 'comp/browser/idle-tracker';
|
||||
|
@ -33,11 +32,6 @@ const ready = (Launcher && Launcher.ready) || $;
|
|||
ready(() => {
|
||||
StartProfiler.milestone('document ready');
|
||||
|
||||
if (AuthReceiver.receive()) {
|
||||
return;
|
||||
}
|
||||
StartProfiler.milestone('checking auth');
|
||||
|
||||
const appModel = new AppModel();
|
||||
StartProfiler.milestone('creating app model');
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import { Features } from 'util/features';
|
||||
|
||||
const AuthReceiver = {
|
||||
receive() {
|
||||
if (!Features.isPopup) {
|
||||
return false;
|
||||
}
|
||||
const opener = window.opener || window.parent;
|
||||
const message = this.urlArgsToMessage(window.location.href);
|
||||
const hasKeys = Object.keys(message).filter(key => key !== 'config').length > 0;
|
||||
if (!hasKeys) {
|
||||
return false;
|
||||
}
|
||||
opener.postMessage(message, window.location.origin);
|
||||
window.close();
|
||||
return true;
|
||||
},
|
||||
|
||||
urlArgsToMessage(url) {
|
||||
const message = {};
|
||||
url.split(/[?#&]/g).forEach(part => {
|
||||
const parts = part.split('=');
|
||||
if (parts.length === 2) {
|
||||
message[parts[0]] = decodeURIComponent(parts[1]);
|
||||
}
|
||||
});
|
||||
return message;
|
||||
}
|
||||
};
|
||||
|
||||
export { AuthReceiver };
|
|
@ -261,8 +261,7 @@ class StorageBase {
|
|||
if (redirectUrl.lastIndexOf('file:', 0) === 0) {
|
||||
redirectUrl = Links.WebApp;
|
||||
}
|
||||
redirectUrl = redirectUrl.split('?')[0];
|
||||
return redirectUrl;
|
||||
return new URL(`oauth-result/${this.name}.html`, redirectUrl).href;
|
||||
}
|
||||
|
||||
_oauthAuthorize(callback) {
|
||||
|
@ -284,7 +283,7 @@ class StorageBase {
|
|||
|
||||
let listener;
|
||||
if (Features.isDesktop) {
|
||||
listener = StorageOAuthListener.listen();
|
||||
listener = StorageOAuthListener.listen(this.name);
|
||||
session.redirectUri = listener.redirectUri;
|
||||
} else {
|
||||
session.redirectUri = this._getOauthRedirectUrl();
|
||||
|
@ -334,15 +333,27 @@ class StorageBase {
|
|||
if (e.origin !== location.origin) {
|
||||
return;
|
||||
}
|
||||
if (e.data && e.data.error) {
|
||||
this.logger.error('OAuth error', e.data.error, e.data.error_description);
|
||||
callback('OAuth: ' + e.data.error);
|
||||
} else if (e.data && e.data.code) {
|
||||
if (!e.data || !e.data.storage || !e.data.search) {
|
||||
this.logger.debug('Skipped empty OAuth message', e.data);
|
||||
return;
|
||||
}
|
||||
if (e.data.storage !== this.name) {
|
||||
this.logger.debug('Skipped OAuth message for another storage', e.data.storage);
|
||||
return;
|
||||
}
|
||||
const data = {};
|
||||
for (const [key, value] of new URLSearchParams(e.data.search).entries()) {
|
||||
data[key] = value;
|
||||
}
|
||||
if (data.error) {
|
||||
this.logger.error('OAuth error', data.error, data.error_description);
|
||||
callback('OAuth: ' + data.error);
|
||||
} else if (data.code) {
|
||||
Events.off('popup-closed', popupClosed);
|
||||
window.removeEventListener('message', windowMessage);
|
||||
this._oauthCodeReceived(e.data, session, callback);
|
||||
this._oauthCodeReceived(data, session, callback);
|
||||
} else {
|
||||
this.logger.debug('Skipped OAuth message', e.data);
|
||||
this.logger.debug('Skipped OAuth message', data);
|
||||
}
|
||||
};
|
||||
Events.on('popup-closed', popupClosed);
|
||||
|
|
|
@ -9,7 +9,7 @@ const logger = new Logger('storage-oauth-listener');
|
|||
const StorageOAuthListener = {
|
||||
server: null,
|
||||
|
||||
listen() {
|
||||
listen(storageName) {
|
||||
if (this.server) {
|
||||
this.stop();
|
||||
}
|
||||
|
@ -20,12 +20,17 @@ const StorageOAuthListener = {
|
|||
});
|
||||
|
||||
const http = Launcher.req('http');
|
||||
let resultHandled = false;
|
||||
const server = http.createServer((req, resp) => {
|
||||
resp.writeHead(200, 'OK', {
|
||||
'Content-Type': 'text/plain; charset=UTF-8'
|
||||
});
|
||||
resp.end(Locale.appBrowserAuthComplete);
|
||||
this.handleResult(req.url, listener);
|
||||
if (!resultHandled) {
|
||||
this.stop();
|
||||
this.handleResult(req.url, listener);
|
||||
resultHandled = true;
|
||||
}
|
||||
});
|
||||
|
||||
const port = DefaultPort;
|
||||
|
@ -43,7 +48,7 @@ const StorageOAuthListener = {
|
|||
listener.emit('ready');
|
||||
});
|
||||
|
||||
listener.redirectUri = `http://localhost:${port}/oauth-result`;
|
||||
listener.redirectUri = `http://localhost:${port}/oauth-result/${storageName}.html`;
|
||||
return listener;
|
||||
},
|
||||
|
||||
|
@ -55,9 +60,12 @@ const StorageOAuthListener = {
|
|||
},
|
||||
|
||||
handleResult(url, listener) {
|
||||
url = new URL(url, listener.redirectUri);
|
||||
if (url.origin + url.pathname !== listener.redirectUri) {
|
||||
logger.info('Skipped result', url, listener.redirectUri);
|
||||
return;
|
||||
}
|
||||
logger.info('OAuth result with code received');
|
||||
this.stop();
|
||||
url = new URL(url, 'http://localhost');
|
||||
const state = url.searchParams.get('state');
|
||||
const code = url.searchParams.get('code');
|
||||
listener.emit('result', { state, code });
|
||||
|
|
|
@ -12,8 +12,7 @@ module.exports = function(grunt) {
|
|||
'inline',
|
||||
'htmlmin',
|
||||
'csp-hashes',
|
||||
'copy:html-dist',
|
||||
'copy:404-dist',
|
||||
'copy:content-dist',
|
||||
'string-replace:service-worker',
|
||||
'string-replace:manifest',
|
||||
'copy:dist-icons',
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
Release notes
|
||||
-------------
|
||||
##### v1.14.2 (2020-05-04)
|
||||
`-` distinct redirect URIs for storage providers
|
||||
|
||||
##### v1.14.1 (2020-05-02)
|
||||
`-` fix #1478: fixed proxy issues with storage providers
|
||||
|
||||
|
|
Loading…
Reference in New Issue