Skip to content

Commit

Permalink
Migrate to a fresh copy of the template and Node 20 (#150)
Browse files Browse the repository at this point in the history
* Migrate to a fresh copy of the template

* Recurse submodules when listing files

Fixes #149

* Adds option to force unlock files upon first failure

Fixes #148

* Pushed missing translations

* Update translations

* Fix mac build
  • Loading branch information
morwoen authored Jul 29, 2024
1 parent cec7b2c commit 8aec3b2
Show file tree
Hide file tree
Showing 92 changed files with 18,676 additions and 17,573 deletions.
8 changes: 5 additions & 3 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@
[
"module-resolver",
{
"cwd": "babelrc",
"cwd": "babelrc",
"alias": {
"Constants": "./app/src/constants",
"Components": "./app/src/components",
"Core": "./app/src/core",
"Pages": "./app/src/pages",
"Redux": "./app/src/redux",
"I18n": "./app/localization"
"I18n": "./app/localization",
"Images": "./resources/images"
}
},
"@babel/plugin-syntax-dynamic-import"
]
],
"presets": [
"@babel/preset-env",
"@babel/preset-react"
"@babel/preset-react",
"@babel/preset-typescript"
]
}
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1
with:
node-version: 16
node-version: 20

- name: Build/release Electron app
uses: samuelmeuli/action-electron-builder@v1
Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,8 @@ dist/

# Logfile specific for development builds
dev-scripts/webpack-dev-server.log
dev-scripts/webpack-dev-server-error.log
dev-scripts/webpack-dev-server-error.log

# License-specific files
license.data
public.key
9 changes: 5 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Contributing guidelines
Please do the following steps before submitting a PR, doing this will help progress your fix into Git Locks Manager.
Please do the following steps before submitting a PR, doing this will help progress your fix into the template.

1. Have you ran `npm run dev` to see if the changes work? Have you checked all of the pages to make sure they are still functional?
2. Have you ran `npm run prod` to see if the changes work in production? Have you checked all of the pages to make sure they are still functional?
3. Have you ran `npm run dist-[windows|mac|linux]` to make sure the app is packaged correctly and works if you install it?
1. Have you ran `npm run test` to ensure the unit tests are working?
2. Have you ran `npm run dev` to see if the changes work? Have you checked all of the pages to make sure they are still functional?
3. Have you ran `npm run prod` to see if the changes work in production? Have you checked all of the pages to make sure they are still functional?
4. Have you ran `npm run dist-[windows|mac|linux|all]` to make sure the app is packaged correctly and works if you install it?
6 changes: 3 additions & 3 deletions app/electron/git.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ function getRepoName(repo) {
function listLockableFiles(repo) {
return Promise.all([
new Promise((resolve, reject) => {
const lsFiles = spawn('git', ['ls-files'], {
const lsFiles = spawn('git', ['ls-files', '--recurse-submodules'], {
cwd: repoRoot(repo),
});
const attrs = spawn('git', ['check-attr', '--stdin', 'lockable'], {
Expand Down Expand Up @@ -249,9 +249,9 @@ function lockFile(repo, file) {
});
}

function unlockFile(repo, file) {
function unlockFile(repo, file, force) {
return new Promise((resolve, reject) => {
exec(`git lfs unlock "${file}" --json`, {
exec(`git lfs unlock "${file}" --json${force ? " --force" : ""}`, {
cwd: repoRoot(repo),
}, (err, stdout, stderr) => {
if (stderr) {
Expand Down
139 changes: 79 additions & 60 deletions app/electron/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ const {
default: installExtension,
REDUX_DEVTOOLS,
REACT_DEVELOPER_TOOLS
} = require('electron-devtools-installer');
} = require("electron-devtools-installer");
const SecureElectronLicenseKeys = require("secure-electron-license-keys");
const Protocol = require("./protocol");
const MenuBuilder = require("./menu");
const i18nextBackend = require("i18next-electron-fs-backend");
const i18nextMainBackend = require("../localization/i18n.mainconfig");
const Store = require('./store');
const Store = require("secure-electron-store").default;
const ContextMenu = require("secure-electron-context-menu").default;
const path = require("path");
const fs = require("fs");
const crypto = require("crypto");
const { autoUpdater } = require("electron-updater");
const debounce = require('lodash/debounce');
const enforceMacOSAppLocation = require('./enforceMacOSAppLocation');
Expand Down Expand Up @@ -50,10 +52,20 @@ async function createWindow() {
}

if (!store) {
store = new Store(app.getPath("userData"));
store = new Store({
path: app.getPath("userData"),
encrypt: false,
minify: false,
debug: true,
});
}

const savedConfig = store.initial();
// Use saved config values for configuring your
// BrowserWindow, for instance.
// NOTE - this config is not passcode protected
// and stores plaintext values
let savedConfig = store.mainInitialStore(fs);

console.log('Stored Config', savedConfig);

const minWidth = 950;
Expand All @@ -78,28 +90,24 @@ async function createWindow() {
nodeIntegrationInSubFrames: false,
contextIsolation: true,
enableRemoteModule: false,
additionalArguments: [`storePath:${app.getPath("userData")}`],
preload: path.join(__dirname, "preload.js"), /* eng-disable PRELOAD_JS_CHECK */
additionalArguments: [`--storePath=${store.sanitizePath(app.getPath("userData"))}`],
preload: path.join(__dirname, "preload.js"),
/* eng-disable PRELOAD_JS_CHECK */
disableBlinkFeatures: "Auxclick"
}
});

// Sets up main.js bindings for our i18next backend
i18nextBackend.mainBindings(ipcMain, win, fs);
// Overwrite the readFileRequest handler in order to use relative paths to the appPath
ipcMain.removeAllListeners(i18nextBackend.readFileRequest);
ipcMain.on(i18nextBackend.readFileRequest, (IpcMainEvent, args) => {
const callback = function (error, data) {
this.webContents.send(i18nextBackend.readFileResponse, {
key: args.key,
error,
data: typeof data !== "undefined" && data !== null ? data.toString() : ""
});
}.bind(win);
fs.readFile(path.resolve(app.getAppPath(), args.filename), "utf8", callback);
});

store.mainBindings(ipcMain, win);
// Sets up main.js bindings for our electron store;
// callback is optional and allows you to use store in main process
const callback = function (success, initialStore) {
console.log(`${!success ? "Un-s" : "S"}uccessfully retrieved store in main process.`);
console.log(initialStore); // {"key1": "value1", ... }
};

store.mainBindings(ipcMain, win, fs, callback);

// Sets up bindings for our custom context menu
ContextMenu.mainBindings(ipcMain, win, Menu, isDev, {
Expand All @@ -113,6 +121,12 @@ async function createWindow() {
}]
});

// Setup bindings for offline license verification
SecureElectronLicenseKeys.mainBindings(ipcMain, win, fs, crypto, {
root: process.cwd(),
version: app.getVersion()
});

// Load app
if (isDev) {
win.loadURL(selfHost);
Expand All @@ -134,7 +148,7 @@ async function createWindow() {
// before the DOM is ready
win.webContents.once("dom-ready", async () => {
await installExtension([REDUX_DEVTOOLS, REACT_DEVELOPER_TOOLS])
.then((name) => console.log(`Added Extension: ${name}`))
.then((name) => console.log(`Added Extension: ${name}`))
.catch((err) => console.log("An error occurred: ", err))
.finally(() => {
require("electron-debug")(); // https://github.com/sindresorhus/electron-debug
Expand Down Expand Up @@ -286,7 +300,7 @@ async function createWindow() {
const partition = "default";
ses.fromPartition(partition) /* eng-disable PERMISSION_REQUEST_HANDLER_JS_CHECK */
.setPermissionRequestHandler((webContents, permission, permCallback) => {
let allowedPermissions = []; // Full list here: https://developer.chrome.com/extensions/declare_permissions#manifest
const allowedPermissions = []; // Full list here: https://developer.chrome.com/extensions/declare_permissions#manifest

if (allowedPermissions.includes(permission)) {
permCallback(true); // Approve permission request
Expand All @@ -310,15 +324,28 @@ async function createWindow() {
// }
// });

menuBuilder = MenuBuilder(app.name);
menuBuilder = MenuBuilder(win, app.name);

// Set up necessary bindings to update the menu items
// based on the current language selected
i18nextMainBackend.on("initialized", (loaded) => {
i18nextMainBackend.changeLanguage("en");
i18nextMainBackend.off("initialized"); // Remove listener to this event as it's not needed anymore
});

// When the i18n framework starts up, this event is called
// (presumably when the default language is initialized)
// BEFORE the "initialized" event is fired - this causes an
// error in the logs. To prevent said error, we only call the
// below code until AFTER the i18n framework has finished its
// "initialized" event.
i18nextMainBackend.on("languageChanged", (lng) => {
locale = lng;
menuBuilder.buildMenu(i18nextMainBackend);
win.webContents.send('menu-update', getMenuList());
// win.webContents.send('menu-update', getMenuList());
if (i18nextMainBackend.isInitialized){
menuBuilder.buildMenu(i18nextMainBackend);
}
});

i18nextMainBackend.changeLanguage(locale);
}

// Needs to be called before app is ready;
Expand Down Expand Up @@ -350,7 +377,7 @@ app.on("window-all-closed", () => {
} else {
i18nextBackend.clearMainBindings(ipcMain);
ContextMenu.clearMainBindings(ipcMain);
store.clearMainBindings(ipcMain);
SecureElectronLicenseKeys.clearMainBindings(ipcMain);
ipcMain.removeAllListeners('select-repo');
ipcMain.removeAllListeners('title-bar-double-click');
ipcMain.removeAllListeners('is-fullscreen');
Expand All @@ -373,18 +400,18 @@ app.on("activate", () => {

// https://electronjs.org/docs/tutorial/security#12-disable-or-limit-navigation
app.on("web-contents-created", (event, contents) => {
contents.on("will-navigate", (contentsEvent, navigationUrl) => { /* eng-disable LIMIT_NAVIGATION_JS_CHECK */
contents.on("will-navigate", (contentsEvent, navigationUrl) => {
/* eng-disable LIMIT_NAVIGATION_JS_CHECK */
const parsedUrl = new URL(navigationUrl);
const validOrigins = [selfHost];

// Log and prevent the app from navigating to a new page if that page's origin is not whitelisted
if (!validOrigins.includes(parsedUrl.origin)) {
console.error(
`The application tried to redirect to the following address: '${parsedUrl}'. This origin is not whitelisted and the attempt to navigate was blocked.`
`The application tried to navigate to the following address: '${parsedUrl}'. This origin is not whitelisted and the attempt to navigate was blocked.`
);

contentsEvent.preventDefault();
return;
}
});

Expand All @@ -399,7 +426,6 @@ app.on("web-contents-created", (event, contents) => {
);

contentsEvent.preventDefault();
return;
}
});

Expand All @@ -412,46 +438,39 @@ app.on("web-contents-created", (event, contents) => {
// Disable Node.js integration
webPreferences.nodeIntegration = false;
});
// enable i18next translations in popup window
contents.on("did-create-window", (window) => {
i18nextBackend.mainBindings(ipcMain, window, fs);
});
// destroy bindings on popup window closed
contents.on("destroyed", () => {
i18nextBackend.clearMainBindings(ipcMain);
});

// https://electronjs.org/docs/tutorial/security#13-disable-or-limit-creation-of-new-windows
contents.on("new-window", (contentsEvent, navigationUrl) => { /* eng-disable LIMIT_NAVIGATION_JS_CHECK */
const parsedUrl = new URL(navigationUrl);
// This code replaces the old "new-window" event handling;
// https://github.com/electron/electron/pull/24517#issue-447670981
contents.setWindowOpenHandler(({
url
}) => {
const parsedUrl = new URL(url);
const validOrigins = [];

// Log and prevent opening up a new window
if (!validOrigins.includes(parsedUrl.origin)) {
console.error(
`The application tried to open a new window at the following address: '${navigationUrl}'. This attempt was blocked.`
`The application tried to open a new window at the following address: '${url}'. This attempt was blocked.`
);

contentsEvent.preventDefault();
return;
return {
action: "deny"
};
}
});
});

// Filter loading any module via remote;
// you shouldn't be using remote at all, though
// https://electronjs.org/docs/tutorial/security#16-filter-the-remote-module
app.on("remote-require", (event, webContents, moduleName) => {
event.preventDefault();
});

// built-ins are modules such as "app"
app.on("remote-get-builtin", (event, webContents, moduleName) => {
event.preventDefault();
});

app.on("remote-get-global", (event, webContents, globalName) => {
event.preventDefault();
});

app.on("remote-get-current-window", (event, webContents) => {
event.preventDefault();
});

app.on("remote-get-current-web-contents", (event, webContents) => {
event.preventDefault();
return {
action: "allow"
};
});
});

autoUpdater.on('update-downloaded', (info) => {
Expand Down
Loading

0 comments on commit 8aec3b2

Please sign in to comment.