Skip to content
This repository has been archived by the owner on Sep 29, 2023. It is now read-only.

Commit

Permalink
Fix injecting multiple css/js files (fix #458) (#1162)
Browse files Browse the repository at this point in the history
* Add ability to inject multiple css/js files

* API doc: Move misplaced macOS shortcuts doc (PR #1158)

When I added this documentation originally, I guess I placed it in the wrong location.

* README: use quotes in example, to divert users from shell globbing pitfalls

Follow-up of #1159 (comment)

* Support opening URLs passed as arg to Nativefied application (fix #405) (PR #1154)

Co-authored-by: Ronan Jouchet <ronan@jouchet.fr>

* macOS: Fix crash when using --tray (fix #527), and invisible icon (fix #942, fix #668) (#1156)

This fixes:

1. A startup crash on macOS when using the `--tray` option; see #527.
  ![image](https://user-images.githubusercontent.com/22625791/115987741-99544600-a5b6-11eb-866a-dadb5640eecb.png)
2. Invisible tray icon on macOS; see #942 and #668.  
   ![image](https://user-images.githubusercontent.com/22625791/115988276-24364000-a5b9-11eb-80c3-561a8a646754.png)

Co-authored-by: Ronan Jouchet <ronan@jouchet.fr>

* API.md / --widevine: document signing apps to make some sites like HBO Max & Udemy work (fix #1147)

* Prompt to confirm when page is attempting to prevent unload (#1163)

Should alleviate part of the issue in #1151

* Add an option to upgrade an existing app (fix #1131) (PR #1138)

This adds a `--upgrade` option to upgrade-in-place an old app, re-using its options it can.
Should help fix #1131

Co-authored-by: Ronan Jouchet <ronan@jouchet.fr>

* Bump to Electron 12.0.5 with Chrome 89.0.4389.128

* Add newly discovered Google internal login page (#1167)

* Fix Widevine by properly listening to widevine-... events, and update docs (fix #1153) (PR #1164)

As documented in #1153, for Widevine support to work properly, we need to listen for the Widevine ready event, and as well for certain sites the app must be signed.

This PR adds the events, and as well adds better documentation on the signing limitation.

This may also help resolve #1147

* Improve suffix creation + tests

* API: clarif in existing doc by the way

* Typo

Co-authored-by: Ronan Jouchet <ronan@jouchet.fr>
Co-authored-by: Ben Curtis <github@nosolutions.com>
Co-authored-by: Fabian Wolf <22625791+fabiwlf@users.noreply.github.com>
  • Loading branch information
4 people committed Apr 30, 2021
1 parent 1ad1844 commit dd6e15f
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 35 deletions.
22 changes: 17 additions & 5 deletions app/src/helpers/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as path from 'path';

import { BrowserWindow } from 'electron';

const INJECT_CSS_PATH = path.join(__dirname, '..', 'inject/inject.css');
export const INJECT_DIR = path.join(__dirname, '..', 'inject');

export function isOSX(): boolean {
return os.platform() === 'darwin';
Expand Down Expand Up @@ -80,17 +80,29 @@ export function linkIsInternal(

export function shouldInjectCss(): boolean {
try {
fs.accessSync(INJECT_CSS_PATH);
return true;
return fs.existsSync(INJECT_DIR);
} catch (e) {
return false;
}
}

export function getCssToInject(): string {
return fs.readFileSync(INJECT_CSS_PATH).toString();
let cssToInject = '';
const cssFiles = fs
.readdirSync(INJECT_DIR, { withFileTypes: true })
.filter(
(injectFile) => injectFile.isFile() && injectFile.name.endsWith('.css'),
)
.map((cssFileStat) =>
path.resolve(path.join(INJECT_DIR, cssFileStat.name)),
);
for (const cssFile of cssFiles) {
console.log(`Injecting CSS file: ${cssFile}`);
const cssFileData = fs.readFileSync(cssFile);
cssToInject += `/* ${cssFile} */\n\n ${cssFileData}\n\n`;
}
return cssToInject;
}

/**
* Helper to print debug messages from the main process in the browser window
*/
Expand Down
20 changes: 17 additions & 3 deletions app/src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import * as path from 'path';

import { ipcRenderer } from 'electron';

const INJECT_JS_PATH = path.join(__dirname, '..', 'inject/inject.js');
export const INJECT_DIR = path.join(__dirname, '..', 'inject');

/**
* Patches window.Notification to:
* - set a callback on a new Notification
Expand All @@ -38,12 +39,25 @@ function setNotificationCallback(createCallback, clickCallback) {
}

function injectScripts() {
const needToInject = fs.existsSync(INJECT_JS_PATH);
const needToInject = fs.existsSync(INJECT_DIR);
if (!needToInject) {
return;
}
// Dynamically require scripts
require(INJECT_JS_PATH);
try {
const jsFiles = fs
.readdirSync(INJECT_DIR, { withFileTypes: true })
.filter(
(injectFile) => injectFile.isFile() && injectFile.name.endsWith('.js'),
)
.map((jsFileStat) => path.join('..', 'inject', jsFileStat.name));
for (const jsFile of jsFiles) {
console.log(`Injecting JS file: ${jsFile}`);
require(jsFile);
}
} catch (error) {
console.warn('Error encoutered injecting JS files', error);
}
}

function notifyNotificationCreate(title, opt) {
Expand Down
2 changes: 1 addition & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ Forces the maximum disk space to be used by the disk cache. Value is given in by
--inject <value>
```

Allows you to inject a javascript or css file. This command can be run multiple times to inject the files.
Allows you to inject javascript or css files. This command can be repeated multiple times to inject multiple files.

_Note:_ The javascript file is loaded _after_ `DOMContentLoaded`, so you can assume the DOM is complete & available.

Expand Down
39 changes: 14 additions & 25 deletions src/build/prepareElectronApp.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import * as fs from 'fs';
import * as crypto from 'crypto';
import * as path from 'path';
import { promisify } from 'util';

import * as log from 'loglevel';

import { copyFileOrDir } from '../helpers/helpers';
import { copyFileOrDir, generateRandomSuffix } from '../helpers/helpers';
import { AppOptions } from '../options/model';

const writeFileAsync = promisify(fs.writeFile);
Expand Down Expand Up @@ -103,6 +102,8 @@ async function maybeCopyScripts(srcs: string[], dest: string): Promise<void> {
return;
}

const supportedInjectionExtensions = ['.css', '.js'];

log.debug(`Copying ${srcs.length} files to inject in app.`);
for (const src of srcs) {
if (!fs.existsSync(src)) {
Expand All @@ -111,41 +112,33 @@ async function maybeCopyScripts(srcs: string[], dest: string): Promise<void> {
);
}

let destFileName: string;
if (path.extname(src) === '.js') {
destFileName = 'inject.js';
} else if (path.extname(src) === '.css') {
destFileName = 'inject.css';
} else {
return;
if (supportedInjectionExtensions.indexOf(path.extname(src)) < 0) {
console.log(`Skipping unsupported injection file: ${src}`);
continue;
}

const postFixHash = generateRandomSuffix();
const destFileName = `inject-${postFixHash}.${path.extname(src)}`;
const destPath = path.join(dest, 'inject', destFileName);
log.debug(`Copying injection file "${src}" to "${destPath}"`);
await copyFileOrDir(src, destPath);
}
}

function normalizeAppName(appName: string, url: string): string {
// use a simple 3 byte random string to prevent collision
const hash = crypto.createHash('md5');
hash.update(url);
const postFixHash = hash.digest('hex').substring(0, 6);
function normalizeAppName(appName: string): string {
// use a simple random string to prevent collisions
const postFixHash = generateRandomSuffix();
const normalized = appName
.toLowerCase()
.replace(/[,:.]/g, '')
.replace(/[\s_]/g, '-');
return `${normalized}-nativefier-${postFixHash}`;
}

function changeAppPackageJsonName(
appPath: string,
name: string,
url: string,
): void {
function changeAppPackageJsonName(appPath: string, name: string): void {
const packageJsonPath = path.join(appPath, '/package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString());
const normalizedAppName = normalizeAppName(name, url);
const normalizedAppName = normalizeAppName(name);
packageJson.name = normalizedAppName;
log.debug(`Updating ${packageJsonPath} 'name' field to ${normalizedAppName}`);

Expand Down Expand Up @@ -189,9 +182,5 @@ export async function prepareElectronApp(
} catch (err) {
log.error('Error copying injection files.', err);
}
changeAppPackageJsonName(
dest,
options.packager.name,
options.packager.targetUrl,
);
changeAppPackageJsonName(dest, options.packager.name);
}
24 changes: 23 additions & 1 deletion src/helpers/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isArgFormatInvalid } from './helpers';
import { isArgFormatInvalid, generateRandomSuffix } from './helpers';

describe('isArgFormatInvalid', () => {
test('is false for correct short args', () => {
Expand Down Expand Up @@ -34,3 +34,25 @@ describe('isArgFormatInvalid', () => {
expect(isArgFormatInvalid('--test-run-with-many-dashes')).toBe(false);
});
});

describe('generateRandomSuffix', () => {
test('is not empty', () => {
expect(generateRandomSuffix()).not.toBe('');
});

test('is not null', () => {
expect(generateRandomSuffix()).not.toBeNull();
});

test('is not undefined', () => {
expect(generateRandomSuffix()).toBeDefined();
});

test('is different per call', () => {
expect(generateRandomSuffix()).not.toBe(generateRandomSuffix());
});

test('respects the length param', () => {
expect(generateRandomSuffix(10).length).toBe(10);
});
});
8 changes: 8 additions & 0 deletions src/helpers/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { spawnSync } from 'child_process';
import * as crypto from 'crypto';
import * as os from 'os';
import * as path from 'path';

Expand Down Expand Up @@ -163,3 +164,10 @@ export function isArgFormatInvalid(arg: string): boolean {
!['--x', '--y'].includes(arg) // exception for long args --{x,y}
);
}

export function generateRandomSuffix(length = 6): string {
const hash = crypto.createHash('md5');
// Add a random salt to help avoid collisions
hash.update(crypto.randomBytes(256));
return hash.digest('hex').substring(0, length);
}

0 comments on commit dd6e15f

Please sign in to comment.