Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions js/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const defaults = {
basePath: "/",
electronOptions: {},
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
cors: "disabled", // or "allowAll" or "allowWhitelist"
corsDomainWhitelist: [], // example: ["api.mapbox.com"]

language: "en",
logLevel: ["INFO", "LOG", "WARN", "ERROR"],
Expand Down
5 changes: 5 additions & 0 deletions js/server_functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ async function isPrivateTarget (url) {
const hostname = parsed.hostname.replace(/^\[|\]$/g, "");

if (hostname.toLowerCase() === "localhost") return true;
if (config.cors === "allowWhitelist" && !config.corsDomainWhitelist.includes(hostname.toLowerCase())) return true;
Comment thread
khassel marked this conversation as resolved.
Outdated

try {
const results = await dns.lookup(hostname, { all: true });
Expand Down Expand Up @@ -68,6 +69,10 @@ function replaceSecretPlaceholder (input) {
* @returns {Promise<void>} A promise that resolves when the response is sent
*/
async function cors (req, res) {
if (config.cors === "disabled") {
Comment thread
khassel marked this conversation as resolved.
Outdated
Log.error("CORS is disabled, you need to enable it in `config.js` by setting `cors` to `allowAll` or `allowWhitelist`");
return false;
Comment thread
khassel marked this conversation as resolved.
Outdated
}
try {
const urlRegEx = "url=(.+?)$";
let url;
Expand Down
19 changes: 19 additions & 0 deletions tests/unit/functions/server_functions_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe("server_functions tests", () => {
let fetchMock;

beforeEach(() => {
global.config = { cors: "allowAll" };
fetchResponseHeadersGet = vi.fn(() => {});
fetchResponseArrayBuffer = vi.fn(() => {});
fetchResponse = {
Expand Down Expand Up @@ -263,4 +264,22 @@ describe("server_functions tests", () => {
expect(response.json).toHaveBeenCalledWith({ error: "Forbidden: private or reserved addresses are not allowed" });
});
});

describe("The isPrivateTarget method with allowWhitelist", () => {
beforeEach(() => {
mockLookup.mockReset();
});

it("Block public unicast IPs if not whitelistet", async () => {
global.config = { cors: "allowWhitelist", corsDomainWhitelist: [] };
mockLookup.mockResolvedValue([{ address: "93.184.216.34", family: 4 }]);
expect(await isPrivateTarget("http://example.com/api")).toBe(true);
});

it("Allow public unicast IPs if whitelistet", async () => {
global.config = { cors: "allowWhitelist", corsDomainWhitelist: ["example.com"] };
mockLookup.mockResolvedValue([{ address: "93.184.216.34", family: 4 }]);
expect(await isPrivateTarget("http://example.com/api")).toBe(false);
});
});
});
Loading