Skip to content

Commit

Permalink
added --whitespace CLI and programmatic API option for generating Tam…
Browse files Browse the repository at this point in the history
…permonkey's @connect headers
  • Loading branch information
Oaphi committed Jan 26, 2022
1 parent fbada6b commit 2ddc249
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 17 deletions.
3 changes: 2 additions & 1 deletion dist/generate.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ export declare type GeneratorOptions<T extends GrantOptions> = {
collapse: boolean;
eol?: string;
grants?: T[];
whitelist?: Array<"self" | "localhost" | "*"> | string[];
run?: RunAtOption;
direct?: boolean;
pretty?: boolean;
};
export declare const generate: <T extends GrantOptions>(type: UserScriptManagerName, { packagePath, output, spaces, eol, collapse, direct, matches, ...rest }: GeneratorOptions<T>) => Promise<string>;
export declare const generate: <T extends GrantOptions>(type: UserScriptManagerName, { packagePath, output, spaces, eol, collapse, direct, matches, whitelist, ...rest }: GeneratorOptions<T>) => Promise<string>;
15 changes: 10 additions & 5 deletions dist/generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const index_3 = require("./generators/violentmonkey/index");
const filesystem_1 = require("./utils/filesystem");
const package_1 = require("./utils/package");
const validators_1 = require("./utils/validators");
const generate = async (type, { packagePath, output, spaces = 4, eol, collapse = true, direct = false, matches = [], ...rest }) => {
const generate = async (type, { packagePath, output, spaces = 4, eol, collapse = true, direct = false, matches = [], whitelist = [], ...rest }) => {
const managerTypeMap = {
greasemonkey: index_1.generateGreasemonkeyHeaders,
tampermonkey: index_2.generateTampermonkeyHeaders,
Expand All @@ -22,9 +22,13 @@ const generate = async (type, { packagePath, output, spaces = 4, eol, collapse =
console.log((0, chalk_1.bgRed) `missing or corrupted package`);
return "";
}
const { invalid, status, valid } = (0, validators_1.validateMatchHeaders)(matches);
if (!status) {
console.log((0, chalk_1.bgRed) `Invalid @match headers:\n` + invalid.join("\n"));
const { invalid: matchInvalid, status: matchStatus, valid: validMatches } = (0, validators_1.validateMatchHeaders)(matches);
if (!matchStatus) {
console.log((0, chalk_1.bgRed) `Invalid @match headers:\n` + matchInvalid.join("\n"));
}
const { invalid: connectInvalid, status: connectStatus, valid: validConnects } = (0, validators_1.validateConnectHeaders)(whitelist);
if (!connectStatus) {
console.log((0, chalk_1.bgRed) `Invalid @connect headers:\n` + connectInvalid.join("\n"));
}
const { status: reqStatus, isValidHomepage, isValidVersion, missing, } = (0, validators_1.validateRequiredHeaders)(parsedPackage);
if (!isValidHomepage) {
Expand All @@ -42,7 +46,8 @@ const generate = async (type, { packagePath, output, spaces = 4, eol, collapse =
const content = await handler(parsedPackage, {
...rest,
collapse,
matches: valid,
matches: validMatches,
whitelist: validConnects,
spaces,
packagePath,
output,
Expand Down
9 changes: 8 additions & 1 deletion dist/generators/tampermonkey/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ exports.generateTampermonkeyHeaders = void 0;
const __1 = require("..");
const common_1 = require("../common");
const monkey_1 = require("../common/monkey");
const generateTampermonkeyHeaders = async (packageInfo, { spaces, matches = [], grants = [], run = "start", pretty = false, collapse = false, }) => {
const generateTampermonkeyHeaders = async (packageInfo, { spaces, whitelist = [], matches = [], grants = [], run = "start", pretty = false, collapse = false, }) => {
const matchHeaders = await (0, __1.generateMatchHeaders)(matches, collapse);
const grantMap = {
set: "GM_setValue",
get: "GM_getValue",
delete: "GM_deleteValue",
list: "GM_listValues",
fetch: "GM_xmlhttpRequest",
unsafe: "unsafeWindow",
change: "window.onurlchange",
close: "window.close",
Expand All @@ -35,6 +36,12 @@ const generateTampermonkeyHeaders = async (packageInfo, { spaces, matches = [],
specialHeaders.push(["source", sourceURL]);
if (homepage)
specialHeaders.push(["homepage", homepage]);
if (grants.includes("fetch")) {
whitelist.forEach((remote) => {
const schemaStripped = remote.replace(/^.+?:\/\//, "");
specialHeaders.push(["connect", schemaStripped]);
});
}
const headers = [
...commonHeaders,
...matchHeaders,
Expand Down
4 changes: 2 additions & 2 deletions dist/generators/tampermonkey/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { CommonGrantOptions, CommonGrants, CommonHeaders, CommonRunAt, CustomHeaders } from "..";
export declare type TampermonkeyGrantOptions = CommonGrantOptions | "close" | "focus" | "change";
export declare type TampermonkeyGrants = CommonGrants | "GM_setValue" | "GM_getValue" | "GM_listValues" | "GM_deleteValue" | "window.close" | "window.focus" | "window.onurlchange";
export declare type TampermonkeyGrantOptions = CommonGrantOptions | "close" | "fetch" | "focus" | "change";
export declare type TampermonkeyGrants = CommonGrants | "GM_setValue" | "GM_getValue" | "GM_listValues" | "GM_deleteValue" | "GM_xmlhttpRequest" | "window.close" | "window.focus" | "window.onurlchange";
export declare type TampermonkeyHeaders = CustomHeaders & CommonHeaders<{
"homepage": string;
"homepageURL": string;
Expand Down
7 changes: 6 additions & 1 deletion dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,16 @@ const sharedOpts = {
default: 4,
type: "number",
},
w: {
alias: "whitelist",
type: "array",
},
pretty: {
type: "boolean",
default: false,
},
};
names.forEach((name) => cli.command(name, `generates ${(0, common_1.scase)(name)} headers`, sharedOpts, ({ c, d, e, g = [], i, m = [], o, p, r = "start", s, pretty }) => void (0, generate_1.generate)(name, {
names.forEach((name) => cli.command(name, `generates ${(0, common_1.scase)(name)} headers`, sharedOpts, ({ c, d, e, g = [], i, m = [], o, p, r = "start", s, pretty, w = [] }) => void (0, generate_1.generate)(name, {
collapse: c,
direct: !!d,
eol: e,
Expand All @@ -79,5 +83,6 @@ names.forEach((name) => cli.command(name, `generates ${(0, common_1.scase)(name)
run: r,
spaces: s,
pretty,
whitelist: w.map(String)
})));
cli.demandCommand().help().parse();
5 changes: 5 additions & 0 deletions dist/utils/validators.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ export declare const validateMatchHeaders: (matches: string[]) => {
status: boolean;
valid: string[];
};
export declare const validateConnectHeaders: (whitelist: string[]) => {
invalid: string[];
status: boolean;
valid: string[];
};
export declare const validateRequiredHeaders: (packageInfo: PackageInfo) => {
status: boolean;
isValidVersion: boolean;
Expand Down
15 changes: 14 additions & 1 deletion dist/utils/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateRequiredHeaders = exports.validateMatchHeaders = exports.getExistingHeadersOffset = void 0;
exports.validateRequiredHeaders = exports.validateConnectHeaders = exports.validateMatchHeaders = exports.getExistingHeadersOffset = void 0;
const os_1 = require("os");
const semver_1 = require("semver");
const validator_1 = __importDefault(require("validator"));
Expand Down Expand Up @@ -64,6 +64,19 @@ const validateMatchHeaders = (matches) => {
};
};
exports.validateMatchHeaders = validateMatchHeaders;
const validateConnectHeaders = (whitelist) => {
const specialWordRegex = /^localhost|self|\*$/;
const ipv4Regex = /^((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.|$)){4}/;
const domainRegex = /^(?!.*?_.*?)(?!(?:[\w]+?\.)?\-[\w\.\-]*?)(?![\w]+?\-\.(?:[\w\.\-]+?))(?=[\w])(?=[\w\.\-]*?\.+[\w\.\-]*?)(?![\w\.\-]{254})(?!(?:\.?[\w\-\.]*?[\w\-]{64,}\.)+?)[\w\.\-]+?(?<![\w\-\.]*?\.[\d]+?)(?<=[\w\-]{2,})(?<![\w\-]{25})$/;
const checks = [specialWordRegex, ipv4Regex, domainRegex];
const invalid = whitelist.filter((remote) => !checks.some((r) => r.test(remote)));
return {
invalid,
status: !invalid.length,
valid: whitelist.filter((r) => !invalid.includes(r))
};
};
exports.validateConnectHeaders = validateConnectHeaders;
const validateRequiredHeaders = (packageInfo) => {
const required = [
"author",
Expand Down
25 changes: 21 additions & 4 deletions src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { replaceFileContent } from "./utils/filesystem";
import { getPackage } from "./utils/package";
import {
getExistingHeadersOffset,
validateConnectHeaders,
validateMatchHeaders,
validateRequiredHeaders
} from "./utils/validators";
Expand All @@ -28,6 +29,7 @@ export type GeneratorOptions<T extends GrantOptions> = {
collapse: boolean;
eol?: string;
grants?: T[];
whitelist?: Array<"self" | "localhost" | "*"> | string[];
run?: RunAtOption;
direct?: boolean;
pretty?: boolean;
Expand All @@ -43,6 +45,7 @@ export const generate = async <T extends GrantOptions>(
collapse = true,
direct = false,
matches = [],
whitelist = [],
...rest
}: GeneratorOptions<T>
) => {
Expand All @@ -60,9 +63,22 @@ export const generate = async <T extends GrantOptions>(
return "";
}

const { invalid, status, valid } = validateMatchHeaders(matches);
if (!status) {
console.log(bgRed`Invalid @match headers:\n` + invalid.join("\n"));
const {
invalid: matchInvalid,
status: matchStatus,
valid: validMatches
} = validateMatchHeaders(matches);
if (!matchStatus) {
console.log(bgRed`Invalid @match headers:\n` + matchInvalid.join("\n"));
}

const {
invalid: connectInvalid,
status: connectStatus,
valid: validConnects
} = validateConnectHeaders(whitelist);
if (!connectStatus) {
console.log(bgRed`Invalid @connect headers:\n` + connectInvalid.join("\n"));
}

const {
Expand Down Expand Up @@ -93,7 +109,8 @@ export const generate = async <T extends GrantOptions>(
const content = await handler(parsedPackage, {
...rest,
collapse,
matches: valid,
matches: validMatches,
whitelist: validConnects,
spaces,
packagePath,
output,
Expand Down
9 changes: 8 additions & 1 deletion src/generators/tampermonkey/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const generateTampermonkeyHeaders: HeaderGenerator<TampermonkeyGrantOptio
packageInfo,
{
spaces,
whitelist = [],
matches = [],
grants = [],
run = "start",
Expand Down Expand Up @@ -71,6 +72,13 @@ export const generateTampermonkeyHeaders: HeaderGenerator<TampermonkeyGrantOptio
if (sourceURL) specialHeaders.push(["source", sourceURL]);
if (homepage) specialHeaders.push(["homepage", homepage]);

if (grants.includes("fetch")) {
whitelist.forEach((remote) => {
const schemaStripped = remote.replace(/^.+?:\/\//, "");
specialHeaders.push(["connect", schemaStripped]);
});
}

const headers = [
...commonHeaders,
...matchHeaders,
Expand All @@ -86,7 +94,6 @@ export const generateTampermonkeyHeaders: HeaderGenerator<TampermonkeyGrantOptio
// @exclude
// @require
// @resource
// @connect
// @antifeature
// @noframes
// @unwrap
Expand Down
7 changes: 6 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ const sharedOpts = {
default: 4,
type: "number",
},
w: {
alias: "whitelist",
type: "array",
},
pretty: {
type: "boolean",
default: false,
Expand All @@ -71,7 +75,7 @@ names.forEach((name) =>
name,
`generates ${scase(name)} headers`,
sharedOpts,
({ c, d, e, g = [], i, m = [], o, p, r = "start", s, pretty }) =>
({ c, d, e, g = [], i, m = [], o, p, r = "start", s, pretty, w = [] }) =>
void generate<GrantOptions>(name, {
collapse: c,
direct: !!d,
Expand All @@ -84,6 +88,7 @@ names.forEach((name) =>
run: r,
spaces: s,
pretty,
whitelist: w.map(String)
})
)
);
Expand Down
22 changes: 22 additions & 0 deletions test/tamper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,26 @@ describe("Tampermonkey", async () => {
const matched = content.match(/@grant\s+(.+)/g) || [];
expect(matched).length(grantOptionsTM.length);
});

it("@connect headers should be generated", async () => {
const whitelist = [
"search.google.com",
"tampermonkey.net",
"self",
"localhost",
"1.2.3.4"
];

const content = await generate("tampermonkey", {
...directCommon,
grants: ["fetch"],
whitelist
});

whitelist.forEach((remote) => {
const escaped = remote.replace(/([./?*()\[\]])/g, "\\$1");
const expr = new RegExp(`@connect\\s+(${escaped})`);
expect(expr.test(content), `failed at ${remote}`).to.be.true;
});
});
});

0 comments on commit 2ddc249

Please sign in to comment.