mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-07-08 14:24:14 +01:00
Improve file handler check to add path separator
Co-authored-by: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com>
This commit is contained in:
@@ -16,11 +16,17 @@ import {
|
||||
getUpdateCachePath,
|
||||
} from './attachments.node.ts';
|
||||
import { createLogger } from '../ts/logging/log.std.ts';
|
||||
import { isPathInside } from '../ts/util/isPathInside.node.ts';
|
||||
|
||||
const log = createLogger('protocol_filter');
|
||||
|
||||
type CallbackType = (response: string | ProtocolResponse) => void;
|
||||
|
||||
export type FileHandlerType = (
|
||||
request: ProtocolRequest,
|
||||
callback: CallbackType
|
||||
) => void;
|
||||
|
||||
function _eliminateAllAfterCharacter(
|
||||
string: string,
|
||||
character: string
|
||||
@@ -50,7 +56,7 @@ export function _urlToPath(
|
||||
return withoutQuerystring;
|
||||
}
|
||||
|
||||
function _createFileHandler({
|
||||
export function _createFileHandler({
|
||||
userDataPath,
|
||||
installPath,
|
||||
isWindows,
|
||||
@@ -58,7 +64,7 @@ function _createFileHandler({
|
||||
userDataPath: string;
|
||||
installPath: string;
|
||||
isWindows: boolean;
|
||||
}) {
|
||||
}): FileHandlerType {
|
||||
const allowedRoots = [
|
||||
userDataPath,
|
||||
installPath,
|
||||
@@ -71,6 +77,9 @@ function _createFileHandler({
|
||||
getTempPath(userDataPath),
|
||||
getUpdateCachePath(userDataPath),
|
||||
];
|
||||
const allowedRootsCased = allowedRoots.map(root =>
|
||||
isWindows ? root.toLowerCase() : root
|
||||
);
|
||||
return (request: ProtocolRequest, callback: CallbackType): void => {
|
||||
let targetPath;
|
||||
|
||||
@@ -102,8 +111,8 @@ function _createFileHandler({
|
||||
return;
|
||||
}
|
||||
|
||||
for (const root of allowedRoots) {
|
||||
if (properCasing.startsWith(isWindows ? root.toLowerCase() : root)) {
|
||||
for (const root of allowedRootsCased) {
|
||||
if (isPathInside(properCasing, root)) {
|
||||
callback({ path: realPath });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,24 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { assert } from 'chai';
|
||||
import type { ProtocolResponse } from 'electron';
|
||||
import * as sinon from 'sinon';
|
||||
|
||||
import { _urlToPath } from '../../../app/protocol_filter.node.ts';
|
||||
import {
|
||||
_createFileHandler,
|
||||
_urlToPath,
|
||||
type FileHandlerType,
|
||||
} from '../../../app/protocol_filter.node.ts';
|
||||
|
||||
describe('Protocol Filter', () => {
|
||||
beforeEach(function (this: Mocha.Context) {
|
||||
this.sandbox = sinon.createSandbox();
|
||||
});
|
||||
|
||||
afterEach(function (this: Mocha.Context) {
|
||||
this.sandbox.restore();
|
||||
});
|
||||
|
||||
describe('_urlToPath', () => {
|
||||
it('returns proper file path for unix style file URI with querystring', () => {
|
||||
const path =
|
||||
@@ -79,4 +93,149 @@ describe('Protocol Filter', () => {
|
||||
assert.strictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_createFileHandler', () => {
|
||||
function testFn({
|
||||
fileHandler,
|
||||
url,
|
||||
expectedResult,
|
||||
}: {
|
||||
fileHandler: FileHandlerType;
|
||||
url: string;
|
||||
expectedResult: string | Partial<ProtocolResponse>;
|
||||
}) {
|
||||
const testCallback = sinon.stub();
|
||||
|
||||
const request = {
|
||||
headers: {},
|
||||
method: 'GET',
|
||||
referrer: '',
|
||||
url,
|
||||
};
|
||||
fileHandler(request, testCallback);
|
||||
sinon.assert.calledWithMatch(testCallback, expectedResult);
|
||||
}
|
||||
|
||||
describe('windows', () => {
|
||||
before(function (this: Mocha.Context) {
|
||||
if (process.platform !== 'win32') {
|
||||
this.skip();
|
||||
}
|
||||
});
|
||||
|
||||
function getFileHandler(): FileHandlerType {
|
||||
return _createFileHandler({
|
||||
userDataPath: 'C:\\Users\\signaluser\\AppData\\Roaming\\Signal',
|
||||
installPath:
|
||||
'C:\\Users\\signaluser\\AppData\\Local\\Programs\\signal-desktop',
|
||||
isWindows: true,
|
||||
});
|
||||
}
|
||||
|
||||
it('allows files in userData', () => {
|
||||
testFn({
|
||||
fileHandler: getFileHandler(),
|
||||
url: 'file:///C:/Users/signaluser/AppData/Roaming/Signal/foo',
|
||||
expectedResult: {
|
||||
path: 'C:\\Users\\signaluser\\AppData\\Roaming\\Signal\\foo',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('disallows files in other places', () => {
|
||||
const fileHandler = getFileHandler();
|
||||
|
||||
testFn({
|
||||
fileHandler,
|
||||
url: 'file:///C:/Windows/foo',
|
||||
expectedResult: { error: -10 },
|
||||
});
|
||||
testFn({
|
||||
fileHandler,
|
||||
url: 'file:///C:/Users/signaluser/AppData/Roaming/Signal Beta/foo',
|
||||
expectedResult: { error: -10 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('macos', () => {
|
||||
before(function (this: Mocha.Context) {
|
||||
if (process.platform === 'win32') {
|
||||
this.skip();
|
||||
}
|
||||
});
|
||||
|
||||
function getFileHandler(): FileHandlerType {
|
||||
return _createFileHandler({
|
||||
userDataPath: '/Users/signaluser/Library/Application Support/Signal',
|
||||
installPath: '/Applications/Signal',
|
||||
isWindows: false,
|
||||
});
|
||||
}
|
||||
|
||||
it('allows files in userData', () => {
|
||||
testFn({
|
||||
fileHandler: getFileHandler(),
|
||||
url: 'file:///Users/signaluser/Library/Application Support/Signal/foo',
|
||||
expectedResult: {
|
||||
path: '/Users/signaluser/Library/Application Support/Signal/foo',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('disallows files in other places', () => {
|
||||
const fileHandler = getFileHandler();
|
||||
|
||||
testFn({
|
||||
fileHandler,
|
||||
url: 'file:///Applications/foo',
|
||||
expectedResult: { error: -10 },
|
||||
});
|
||||
testFn({
|
||||
fileHandler,
|
||||
url: 'file:///Users/signaluser/Library/Application Support/Signal Beta/foo',
|
||||
expectedResult: { error: -10 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('linux', () => {
|
||||
before(function (this: Mocha.Context) {
|
||||
if (process.platform === 'win32') {
|
||||
this.skip();
|
||||
}
|
||||
});
|
||||
|
||||
function getFileHandler(): FileHandlerType {
|
||||
return _createFileHandler({
|
||||
userDataPath: '/home/signaluser/.config/Signal',
|
||||
installPath: '/usr/bin/signal-desktop',
|
||||
isWindows: false,
|
||||
});
|
||||
}
|
||||
|
||||
it('allows files in userData', () => {
|
||||
testFn({
|
||||
fileHandler: getFileHandler(),
|
||||
url: 'file:///home/signaluser/.config/Signal/foo',
|
||||
expectedResult: { path: '/home/signaluser/.config/Signal/foo' },
|
||||
});
|
||||
});
|
||||
|
||||
it('disallows files in other places', () => {
|
||||
const fileHandler = getFileHandler();
|
||||
|
||||
testFn({
|
||||
fileHandler,
|
||||
url: 'file:///usr/bin/foo',
|
||||
expectedResult: { error: -10 },
|
||||
});
|
||||
testFn({
|
||||
fileHandler,
|
||||
url: 'file:///home/signaluser/.config/Signal Beta/foo',
|
||||
expectedResult: { error: -10 },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user