Skip to content

Commit

Permalink
Fix buggy partial startup on macOS due to flag added by Gatekeeper/XP…
Browse files Browse the repository at this point in the history
…rotect (atom#21861)

macOS Gatekeeper adds a flag ("-psn_0_[six or seven digits here]") when it intercepts Atom launches.
This happens for fresh downloads, new installs, or first launches after upgrading).
 We don't need this flag, and yargs interprets it as many short flags. So, we filter it out.
  • Loading branch information
DeeDeeG authored Jan 18, 2021
1 parent 1e10a0a commit 7928a1b
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 3 deletions.
4 changes: 2 additions & 2 deletions spec/main-process/atom-application.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ describe('AtomApplication', function() {
});

it('opens a file to a specific line number and column', async function() {
await scenario.open(parseCommandLine('b/2.md:12:5'));
await scenario.open(parseCommandLine(['b/2.md:12:5']));
await scenario.assert('[_ 2.md]');

const w = scenario.getWindow(0);
Expand All @@ -750,7 +750,7 @@ describe('AtomApplication', function() {
});

it('truncates trailing whitespace and colons', async function() {
await scenario.open(parseCommandLine('b/2.md:: '));
await scenario.open(parseCommandLine(['b/2.md:: ']));
await scenario.assert('[_ 2.md]');

const w = scenario.getWindow(0);
Expand Down
88 changes: 88 additions & 0 deletions spec/main-process/parse-command-line.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,65 @@ describe('parseCommandLine', () => {
]);
assert.deepEqual(args.pathsToOpen, ['/some/path']);
});

// The "underscore flag" with no "non-flag argument" after it
// is the minimal reproducer for the macOS Gatekeeper startup bug.
// By default, it causes the addition of boolean "true"s into yargs' "non-flag argument" array: `argv._`
// Whereas we do string-only operations on these arguments, expecting them to be paths or URIs.
describe('and --_ or -_ are passed', () => {
it('does not attempt to parse booleans as paths or URIs', () => {
const args = parseCommandLine([
'--_',
'/some/path',
'-_',
'-_',
'some/other/path',
'atom://test/url',
'--_',
'atom://other/url',
'-_',
'./another-path.file',
'-_',
'-_',
'-_'
]);
assert.deepEqual(args.urlsToOpen, [
'atom://test/url',
'atom://other/url'
]);
assert.deepEqual(args.pathsToOpen, [
'/some/path',
'some/other/path',
'./another-path.file'
]);
});
});

describe('and a non-flag number is passed as an argument', () => {
it('does not attempt to parse numbers as paths or URIs', () => {
const args = parseCommandLine([
'43',
'/some/path',
'22',
'97',
'some/other/path',
'atom://test/url',
'885',
'atom://other/url',
'42',
'./another-path.file'
]);
assert.deepEqual(args.urlsToOpen, [
'atom://test/url',
'atom://other/url'
]);
assert.deepEqual(args.pathsToOpen, [
'/some/path',
'some/other/path',
'./another-path.file'
]);
});
});
});

describe('when --uri-handler is passed', () => {
Expand All @@ -41,4 +100,33 @@ describe('parseCommandLine', () => {
assert.deepEqual(args.pathsToOpen, []);
});
});

describe('when evil macOS Gatekeeper flag "-psn_0_[six or seven digits here]" is passed', () => {
it('ignores any arguments starting with "-psn_"', () => {
const getPsnFlag = () => {
return `-psn_0_${Math.floor(Math.random() * 10_000_000)}`;
};
const args = parseCommandLine([
getPsnFlag(),
'/some/path',
getPsnFlag(),
getPsnFlag(),
'some/other/path',
'atom://test/url',
getPsnFlag(),
'atom://other/url',
'-psn_ Any argument starting with "-psn_" should be ignored, even this one.',
'./another-path.file'
]);
assert.deepEqual(args.urlsToOpen, [
'atom://test/url',
'atom://other/url'
]);
assert.deepEqual(args.pathsToOpen, [
'/some/path',
'some/other/path',
'./another-path.file'
]);
});
});
});
12 changes: 11 additions & 1 deletion src/main-process/parse-command-line.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ const yargs = require('yargs');
const { app } = require('electron');

module.exports = function parseCommandLine(processArgs) {
const options = yargs(processArgs).wrap(yargs.terminalWidth());
// macOS Gatekeeper adds a flag ("-psn_0_[six or seven digits here]") when it intercepts Atom launches.
// (This happens for fresh downloads, new installs, or first launches after upgrading).
// We don't need this flag, and yargs interprets it as many short flags. So, we filter it out.
const filteredArgs = processArgs.filter(arg => !arg.startsWith('-psn_'));

const options = yargs(filteredArgs).wrap(yargs.terminalWidth());
const version = app.getVersion();
options.usage(
dedent`Atom Editor v${version}
Expand Down Expand Up @@ -187,6 +192,11 @@ module.exports = function parseCommandLine(processArgs) {
let devMode = args['dev'];

for (const path of args._) {
if (typeof path !== 'string') {
// Sometimes non-strings (such as numbers or boolean true) get into args._
// In the next block, .startsWith() only works on strings. So, skip non-string arguments.
continue;
}
if (path.startsWith('atom://')) {
urlsToOpen.push(path);
} else {
Expand Down

0 comments on commit 7928a1b

Please sign in to comment.