mirror of https://github.com/keeweb/keeweb
option to create a portable installation
parent
a2bf157b01
commit
4d678184f3
43
Gruntfile.js
43
Gruntfile.js
|
@ -29,7 +29,8 @@ module.exports = function(grunt) {
|
|||
const zipCommentPlaceholder =
|
||||
zipCommentPlaceholderPart + '.'.repeat(512 - zipCommentPlaceholderPart.length);
|
||||
const electronVersion = pkg.dependencies.electron.replace(/^\D/, '');
|
||||
const getCodeSignConfig = () => require('./keys/codesign.json');
|
||||
const skipSign = grunt.option('skip-sign');
|
||||
const getCodeSignConfig = () => (skipSign ? undefined : require('./keys/codesign.json'));
|
||||
|
||||
const webpackOptions = {
|
||||
date,
|
||||
|
@ -306,24 +307,28 @@ module.exports = function(grunt) {
|
|||
appBundleId: 'net.antelle.keeweb',
|
||||
appCategoryType: 'public.app-category.productivity',
|
||||
extendInfo: 'package/osx/extend.plist',
|
||||
osxSign: {
|
||||
get identity() {
|
||||
return getCodeSignConfig().identities.app;
|
||||
},
|
||||
hardenedRuntime: true,
|
||||
entitlements: 'package/osx/entitlements.mac.plist',
|
||||
'entitlements-inherit': 'package/osx/entitlements.mac.plist',
|
||||
'gatekeeper-assess': false
|
||||
},
|
||||
osxNotarize: {
|
||||
get appleId() {
|
||||
return getCodeSignConfig().appleId;
|
||||
},
|
||||
appleIdPassword: '@keychain:AC_PASSWORD',
|
||||
get ascProvider() {
|
||||
return getCodeSignConfig().teamId;
|
||||
}
|
||||
},
|
||||
osxSign: skipSign
|
||||
? undefined
|
||||
: {
|
||||
get identity() {
|
||||
return getCodeSignConfig().identities.app;
|
||||
},
|
||||
hardenedRuntime: true,
|
||||
entitlements: 'package/osx/entitlements.mac.plist',
|
||||
'entitlements-inherit': 'package/osx/entitlements.mac.plist',
|
||||
'gatekeeper-assess': false
|
||||
},
|
||||
osxNotarize: skipSign
|
||||
? undefined
|
||||
: {
|
||||
get appleId() {
|
||||
return getCodeSignConfig().appleId;
|
||||
},
|
||||
appleIdPassword: '@keychain:AC_PASSWORD',
|
||||
get ascProvider() {
|
||||
return getCodeSignConfig().teamId;
|
||||
}
|
||||
},
|
||||
afterCopy: [
|
||||
(buildPath, electronVersion, platform, arch, callback) => {
|
||||
if (path.basename(buildPath) !== 'app') {
|
||||
|
|
|
@ -16,6 +16,10 @@ let restartPending = false;
|
|||
let mainWindowPosition = {};
|
||||
let updateMainWindowPositionTimeout = null;
|
||||
|
||||
const windowPositionFileName = 'window-position.json';
|
||||
const appSettingsFileName = 'app-settings.json';
|
||||
const portableConfigFileName = 'keeweb-portable.json';
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
if (!gotTheLock) {
|
||||
app.quit();
|
||||
|
@ -23,11 +27,9 @@ if (!gotTheLock) {
|
|||
|
||||
perfTimestamps?.push({ name: 'single instance lock', ts: process.hrtime() });
|
||||
|
||||
initUserDataDir();
|
||||
|
||||
let openFile = process.argv.filter(arg => /\.kdbx$/i.test(arg))[0];
|
||||
const overrideUserDataDir = process.env.KEEWEB_PORTABLE_EXECUTABLE_DIR;
|
||||
const userDataDir = overrideUserDataDir || app.getPath('userData');
|
||||
const windowPositionFileName = path.join(userDataDir, 'window-position.json');
|
||||
const appSettingsFileName = path.join(userDataDir, 'app-settings.json');
|
||||
|
||||
const isDev = !__dirname.endsWith('.asar');
|
||||
const htmlPath =
|
||||
|
@ -160,8 +162,10 @@ app.reqNative = function(mod) {
|
|||
};
|
||||
|
||||
function readAppSettings() {
|
||||
const appSettingsFilePath = path.join(app.getPath('userData'), appSettingsFileName);
|
||||
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(appSettingsFileName, 'utf8'));
|
||||
return JSON.parse(fs.readFileSync(appSettingsFilePath, 'utf8'));
|
||||
} catch (e) {
|
||||
return null;
|
||||
} finally {
|
||||
|
@ -310,12 +314,17 @@ function saveMainWindowPosition() {
|
|||
}
|
||||
delete mainWindowPosition.changed;
|
||||
try {
|
||||
fs.writeFileSync(windowPositionFileName, JSON.stringify(mainWindowPosition), 'utf8');
|
||||
fs.writeFileSync(
|
||||
path.join(app.getPath('userData'), windowPositionFileName),
|
||||
JSON.stringify(mainWindowPosition),
|
||||
'utf8'
|
||||
);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function restoreMainWindowPosition() {
|
||||
fs.readFile(windowPositionFileName, 'utf8', (e, data) => {
|
||||
const fileName = path.join(app.getPath('userData'), windowPositionFileName);
|
||||
fs.readFile(fileName, 'utf8', (e, data) => {
|
||||
if (data) {
|
||||
mainWindowPosition = JSON.parse(data);
|
||||
if (mainWindow && mainWindowPosition) {
|
||||
|
@ -477,11 +486,44 @@ function subscribePowerEvents() {
|
|||
perfTimestamps?.push({ name: 'subscribing to power events', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
function setEnv() {
|
||||
if (overrideUserDataDir) {
|
||||
app.setPath('userData', overrideUserDataDir);
|
||||
function initUserDataDir() {
|
||||
let execPath = process.execPath;
|
||||
let isPortable;
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
isPortable = !execPath.startsWith('/Applications/');
|
||||
if (isPortable) {
|
||||
execPath = execPath.substring(0, execPath.indexOf('.app'));
|
||||
}
|
||||
break;
|
||||
case 'win32':
|
||||
isPortable = !execPath.includes('Program Files');
|
||||
break;
|
||||
case 'linux':
|
||||
isPortable = !execPath.startsWith('/usr/') && !execPath.startsWith('/opt/');
|
||||
break;
|
||||
}
|
||||
|
||||
if (isPortable) {
|
||||
const portableConfigDir = path.dirname(execPath);
|
||||
const portableConfigPath = path.join(portableConfigDir, portableConfigFileName);
|
||||
|
||||
if (fs.existsSync(portableConfigPath)) {
|
||||
const portableConfig = JSON.parse(fs.readFileSync(portableConfigPath, 'utf8'));
|
||||
const portableUserDataDir = path.resolve(portableConfigDir, portableConfig.userDataDir);
|
||||
|
||||
if (!fs.existsSync(portableUserDataDir)) {
|
||||
fs.mkdirSync(portableUserDataDir);
|
||||
}
|
||||
|
||||
app.setPath('userData', portableUserDataDir);
|
||||
}
|
||||
}
|
||||
|
||||
perfTimestamps?.push({ name: 'userdata dir', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
function setEnv() {
|
||||
if (
|
||||
process.platform === 'linux' &&
|
||||
['Pantheon', 'Unity:Unity7'].indexOf(process.env.XDG_CURRENT_DESKTOP) !== -1
|
||||
|
@ -507,7 +549,7 @@ function deleteOldTempFiles() {
|
|||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
const tempPath = path.join(userDataDir, 'temp');
|
||||
const tempPath = path.join(app.getPath('userData'), 'temp');
|
||||
if (fs.existsSync(tempPath)) {
|
||||
deleteRecursive(tempPath);
|
||||
}
|
||||
|
|
|
@ -51,6 +51,12 @@ module.exports = function(grunt) {
|
|||
'sign-dist'
|
||||
]);
|
||||
|
||||
grunt.registerTask('dev-desktop-darwin', 'Build a macOS app in dev environment', [
|
||||
'default',
|
||||
'build-desktop-app-content',
|
||||
'build-desktop-executables-darwin'
|
||||
]);
|
||||
|
||||
grunt.registerTask('cordova', 'Build cordova app', [
|
||||
'default',
|
||||
'build-cordova'
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
"build-beta": "grunt --beta && cp dist/index.html ../keeweb-beta/index.html && cd ../keeweb-beta && git add index.html && git commit -a -m 'beta' && git push origin master",
|
||||
"electron": "cross-env ELECTRON_DISABLE_SECURITY_WARNINGS=1 KEEWEB_HTML_PATH=http://localhost:8085 electron desktop",
|
||||
"dev": "grunt dev",
|
||||
"dev-desktop": "grunt dev-desktop-darwin --skip-sign",
|
||||
"babel-helpers": "babel-external-helpers -l 'slicedToArray,toConsumableArray,defineProperty,typeof' -t global > app/lib/babel-helpers.js"
|
||||
},
|
||||
"author": {
|
||||
|
|
|
@ -4,6 +4,7 @@ Release notes
|
|||
`+` YubiKey integration in two modes: OATH and Challenge-Response
|
||||
`+` #557: Argon2 speed improvements in desktop apps
|
||||
`+` #1503: ARM64 Windows support
|
||||
`+` #1480: option to create a portable installation
|
||||
`+` #1400: auto-apply tag when creating new entry in tag view
|
||||
`+` #1342: hint that the data will be stored in unencrypted form after exporting
|
||||
`*` #1471: WebDAV url validation, only HTTPS is allowed
|
||||
|
|
Loading…
Reference in New Issue