identity: require aliases to be anchored (#1413)

Summary:
All the documentation and tests seem to be assuming that aliases must be
anchored: `github/torvalds`, but not `some github/torvalds stuff`.
JavaScript regular expressions aren’t anchored by default; this commit
adds explicit anchoring and adds tests.

Test Plan:
Unit tests added.

wchargin-branch: alias-anchor
This commit is contained in:
William Chargin 2019-10-19 09:06:09 -07:00 committed by GitHub
parent b2943390dc
commit 28b25c2910
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 6 deletions

View File

@ -17,26 +17,36 @@ import {userAddress as discourseAddress} from "../discourse/address";
*/ */
export type Alias = string; export type Alias = string;
const _VALID_ALIAS = /^(\w+)[/](.*)$/;
const _VALID_GITHUB_NAME = /^@?([0-9a-z_-]+)$/i;
const _VALID_DISCOURSE_NAME = /^@?([0-9a-z_-]+)$/i;
export function resolveAlias( export function resolveAlias(
alias: Alias, alias: Alias,
discourseUrl: string | null discourseUrl: string | null
): NodeAddressT { ): NodeAddressT {
const re = /(\w+)\/@?([A-Za-z0-9-_]+)/g; const match = alias.match(_VALID_ALIAS);
const match = re.exec(alias);
if (match == null) { if (match == null) {
throw new Error(`Unable to parse alias: ${alias}`); throw new Error(`Unable to parse alias: ${alias}`);
} }
const prefix = match[1]; const [_, prefix, name] = match;
const name = match[2];
switch (prefix) { switch (prefix) {
case "github": { case "github": {
return githubAddress(name); const match = name.match(_VALID_GITHUB_NAME);
if (!match) {
throw new Error(`Invalid GitHub username: ${name}`);
}
return githubAddress(match[1]);
} }
case "discourse": { case "discourse": {
if (discourseUrl == null) { if (discourseUrl == null) {
throw new Error(`Can't parse alias ${alias} without Discourse url`); throw new Error(`Can't parse alias ${alias} without Discourse url`);
} }
return discourseAddress(discourseUrl, name); const match = name.match(_VALID_DISCOURSE_NAME);
if (!match) {
throw new Error(`Invalid Discourse username: ${name}`);
}
return discourseAddress(discourseUrl, match[1]);
} }
default: default:
throw new Error(`Unknown type for alias: ${alias}`); throw new Error(`Unknown type for alias: ${alias}`);

View File

@ -13,6 +13,16 @@ describe("src/plugins/identity/alias", () => {
it("an alias without a /-delimited prefix", () => { it("an alias without a /-delimited prefix", () => {
expect(() => resolveAlias("@credbot", null)).toThrow("Unable to parse"); expect(() => resolveAlias("@credbot", null)).toThrow("Unable to parse");
}); });
it("an alias not anchored to start of string", () => {
expect(() => resolveAlias("my github/@credbot", null)).toThrow(
"Unable to parse"
);
});
it("an alias not anchored to end of string", () => {
expect(() => resolveAlias("github/@credbot friend", null)).toThrow(
"Invalid GitHub username"
);
});
it("an alias with an unknown prefix", () => { it("an alias with an unknown prefix", () => {
expect(() => resolveAlias("foo/bar", null)).toThrow( expect(() => resolveAlias("foo/bar", null)).toThrow(
"Unknown type for alias" "Unknown type for alias"
@ -23,6 +33,16 @@ describe("src/plugins/identity/alias", () => {
"without Discourse url" "without Discourse url"
); );
}); });
it("a github login with invalid characters", () => {
expect(() => resolveAlias("github/!@#$", null)).toThrow(
"Invalid GitHub username"
);
});
it("a discourse login with invalid characters", () => {
expect(() => resolveAlias("discourse/!@#$", "url")).toThrow(
"Invalid Discourse username"
);
});
}); });
describe("works on", () => { describe("works on", () => {
it("a github login", () => { it("a github login", () => {