Skip to content

Commit a17624c

Browse files
committed
[server] generate better workspace ids
1 parent 1ac8fbe commit a17624c

11 files changed

+92
-84
lines changed

components/gitpod-protocol/src/util/gitpod-host-url.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export interface UrlChange {
1212
}
1313
export type UrlUpdate = UrlChange | Partial<URL>;
1414

15-
export const workspaceIDRegex = /([a-z0-9]{4,8}-)+([a-z0-9]{12})/;
15+
export const workspaceIDRegex = /([a-z]+-[a-z]+-[a-z]+-[0-9a-f]{8})/;
1616

1717
export class GitpodHostUrl {
1818
readonly url: URL;

components/gitpod-protocol/src/util/parse-workspace-id.spec.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,23 @@ const expect = chai.expect;
1313
export class ParseWorkspaceIdTest {
1414

1515
@test public parseWorkspaceIdFromHostname_fromWorkspaceLocation() {
16-
const actual = parseWorkspaceIdFromHostname("b7e0eaf8-ec73-44ec-81ea-04859263b656.ws-eu01.gitpod.io");
17-
expect(actual).to.equal("b7e0eaf8-ec73-44ec-81ea-04859263b656");
16+
const actual = parseWorkspaceIdFromHostname("tight-moccasin-ferret-155799b3.ws-eu01.gitpod.io");
17+
expect(actual).to.equal("tight-moccasin-ferret-155799b3");
1818
}
1919

2020
@test public parseWorkspaceIdFromHostname_fromWorkspacePortLocation() {
21-
const actual = parseWorkspaceIdFromHostname("3000-b7e0eaf8-ec73-44ec-81ea-04859263b656.ws-eu01.gitpod.io");
22-
expect(actual).to.equal("b7e0eaf8-ec73-44ec-81ea-04859263b656");
21+
const actual = parseWorkspaceIdFromHostname("3000-tight-moccasin-ferret-155799b3.ws-eu01.gitpod.io");
22+
expect(actual).to.equal("tight-moccasin-ferret-155799b3");
2323
}
2424

2525
@test public parseWorkspaceIdFromHostname_fromWorkspacePortLocationWithWebviewPrefix() {
26-
const actual = parseWorkspaceIdFromHostname("webview-3000-b7e0eaf8-ec73-44ec-81ea-04859263b656.ws-eu01.gitpod.io");
27-
expect(actual).to.equal("b7e0eaf8-ec73-44ec-81ea-04859263b656");
26+
const actual = parseWorkspaceIdFromHostname("webview-3000-tight-moccasin-ferret-155799b3.ws-eu01.gitpod.io");
27+
expect(actual).to.equal("tight-moccasin-ferret-155799b3");
2828
}
2929

3030
@test public parseWorkspaceIdFromHostname_fromWorkspacePortLocationWithWebviewPrefixCustomHost() {
31-
const actual = parseWorkspaceIdFromHostname("webview-3000-ca81a50f-09d7-465c-acd9-264a747d5351.ws-eu01.some.subdomain.somehost.com");
32-
expect(actual).to.equal("ca81a50f-09d7-465c-acd9-264a747d5351");
31+
const actual = parseWorkspaceIdFromHostname("webview-3000-tight-moccasin-ferret-155799b3.ws-eu01.some.subdomain.somehost.com");
32+
expect(actual).to.equal("tight-moccasin-ferret-155799b3");
3333
}
3434
}
3535
module.exports = new ParseWorkspaceIdTest()

components/gitpod-protocol/src/util/parse-workspace-id.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@
77

88
/**
99
* Hostname may be of the form:
10-
* - b7e0eaf8-ec73-44ec-81ea-04859263b656.ws-eu01.gitpod.io
11-
* - 1234-b7e0eaf8-ec73-44ec-81ea-04859263b656.ws-eu01.gitpod.io
12-
* - webview-1234-b7e0eaf8-ec73-44ec-81ea-04859263b656.ws-eu01.gitpod.io (or any other string replacing webview)
10+
* - tight-moccasin-ferret-155799b3.ws-eu01.gitpod.io
11+
* - 1234-tight-moccasin-ferret-155799b3.ws-eu01.gitpod.io
12+
* - webview-1234-tight-moccasin-ferret-155799b3.ws-eu01.gitpod.io (or any other string replacing webview)
1313
* @param hostname The hostname the request is headed to
1414
*/
1515
export const parseWorkspaceIdFromHostname = function(hostname: string) {
1616
// We need to parse the workspace id precisely here to get the case '<some-str>-<port>-<wsid>.ws.' right
17-
const wsIdExpression = /([a-z][0-9a-z]+\-([0-9a-z]+\-){3}[0-9a-z]+)\.ws/g;
17+
const wsIdExpression = /([a-z]+\-)?([0-9]+\-)?(([a-z]+\-){3}[0-9a-z]{8})\.ws/g;
1818
const match = wsIdExpression.exec(hostname);
1919
if (match && match.length >= 2) {
20-
return match[1];
20+
return match[3];
2121
} else {
2222
return undefined;
2323
}

components/server/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"request": "^2.87.0",
7777
"request-promise": "^4.2.2",
7878
"swot-js": "^1.0.3",
79+
"unique-names-generator": "^4.3.1",
7980
"uuid": "^3.1.0",
8081
"vscode-ws-jsonrpc": "^0.2.0",
8182
"ws": "^5.2.2"

components/server/src/express-util.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ const HOSTURL_HOSTNAME = "gpl-2732-ws-csrf.staging.gitpod.io";
1313
describe('express-util', function() {
1414
describe('isAllowedWebsocketDomain', function() {
1515
it('should return false for workspace-port locations', function() {
16-
const result = isAllowedWebsocketDomain("http://3000-aee7da59-2b15-42a6-9773-2546ed487149.ws-eu.gpl-2732-ws-csrf.staging.gitpod.io", HOSTURL_HOSTNAME);
16+
const result = isAllowedWebsocketDomain("http://3000-tight-moccasin-ferret-155799b3.ws-eu.gpl-2732-ws-csrf.staging.gitpod.io", HOSTURL_HOSTNAME);
1717
expect(result).to.be.false;
1818
});
1919

2020
it('should return true for workspace locations', function() {
21-
const result = isAllowedWebsocketDomain("http://aee7da59-2b15-42a6-9773-2546ed487149.ws-eu.gpl-2732-ws-csrf.staging.gitpod.io", HOSTURL_HOSTNAME);
21+
const result = isAllowedWebsocketDomain("http://tight-moccasin-ferret-155799b3.ws-eu.gpl-2732-ws-csrf.staging.gitpod.io", HOSTURL_HOSTNAME);
2222
expect(result).to.be.true;
2323
});
2424

components/server/src/express-util.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ const looksLikeWorkspaceHostname = (originHostname: string, gitpodHostName: stri
9595
return false;
9696
}
9797

98-
return parts[0].split("-").length === 5;
98+
return parts[0].split("-").length === 4;
9999
};
100100

101101
export function saveSession(reqOrSession: express.Request | Express.Session): Promise<void> {

components/server/src/workspace/workspace-factory.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { ImageBuilderClientProvider } from '@gitpod/image-builder/lib';
2121
import { TracedWorkspaceDB, DBWithTracing } from '@gitpod/gitpod-db/lib/traced-db';
2222
import { ImageSourceProvider } from './image-source-provider';
2323
import { TheiaPluginService } from '../theia-plugin/theia-plugin-service';
24+
import { uniqueNamesGenerator, adjectives, colors, animals } from 'unique-names-generator';
2425

2526
@injectable()
2627
export class WorkspaceFactory {
@@ -188,12 +189,13 @@ export class WorkspaceFactory {
188189
}
189190

190191
protected generateWorkspaceId(): string {
191-
var uuid
192-
do {
193-
uuid = uuidv4()
194-
}
195-
while (uuid.charAt(0).match("[0-9]") != null) // No numbers as first char, as we use this id as DNS name
196-
return uuid
192+
const randomName: string = uniqueNamesGenerator({
193+
dictionaries: [adjectives, colors, animals],
194+
separator: '-',
195+
length: 3,
196+
});
197+
198+
return randomName + "-" + uuidv4().substring(0,8);
197199
}
198200

199201
}

components/ws-proxy/pkg/proxy/routes_test.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ var (
4040
IDEPublicPort: "23000",
4141
InstanceID: "1943c611-a014-4f4d-bf5d-14ccf0123c60",
4242
Ports: []PortInfo{
43-
{PortSpec: api.PortSpec{Port: 28080, Target: 38080, Url: "https://28080-c95fd41c-13d9-4d51-b282-e2be09de207f.test-domain.com/", Visibility: api.PortVisibility_PORT_VISIBILITY_PUBLIC}},
43+
{PortSpec: api.PortSpec{Port: 28080, Target: 38080, Url: "https://28080-regional-amaranth-smelt-9ba20cc1.test-domain.com/", Visibility: api.PortVisibility_PORT_VISIBILITY_PUBLIC}},
4444
},
45-
URL: "https://c95fd41c-13d9-4d51-b282-e2be09de207f.test-domain.com/",
46-
WorkspaceID: "c95fd41c-13d9-4d51-b282-e2be09de207f",
45+
URL: "https://regional-amaranth-smelt-9ba20cc1.test-domain.com/",
46+
WorkspaceID: "regional-amaranth-smelt-9ba20cc1",
4747
},
4848
}
4949

@@ -413,31 +413,31 @@ func TestRoutes(t *testing.T) {
413413
},
414414
{
415415
Desc: "non-existent authorized GET /",
416-
Request: modifyRequest(httptest.NewRequest("GET", strings.ReplaceAll(workspaces[0].URL, "c95fd41c", "00000000"), nil),
416+
Request: modifyRequest(httptest.NewRequest("GET", strings.ReplaceAll(workspaces[0].URL, "regional", "blabla"), nil),
417417
addHostHeader,
418418
addOwnerToken(workspaces[0].InstanceID, workspaces[0].Auth.OwnerToken),
419419
),
420420
Expectation: Expectation{
421421
Status: http.StatusFound,
422422
Header: http.Header{
423423
"Content-Type": {"text/html; charset=utf-8"},
424-
"Location": {"https://test-domain.com/start/#00000000-13d9-4d51-b282-e2be09de207f"},
424+
"Location": {"https://test-domain.com/start/#blabla-amaranth-smelt-9ba20cc1"},
425425
},
426-
Body: ("<a href=\"https://test-domain.com/start/#00000000-13d9-4d51-b282-e2be09de207f\">Found</a>.\n\n"),
426+
Body: ("<a href=\"https://test-domain.com/start/#blabla-amaranth-smelt-9ba20cc1\">Found</a>.\n\n"),
427427
},
428428
},
429429
{
430430
Desc: "non-existent unauthorized GET /",
431-
Request: modifyRequest(httptest.NewRequest("GET", strings.ReplaceAll(workspaces[0].URL, "c95fd41c", "00000000"), nil),
431+
Request: modifyRequest(httptest.NewRequest("GET", strings.ReplaceAll(workspaces[0].URL, "regional", "blabla"), nil),
432432
addHostHeader,
433433
),
434434
Expectation: Expectation{
435435
Status: http.StatusFound,
436436
Header: http.Header{
437437
"Content-Type": {"text/html; charset=utf-8"},
438-
"Location": {"https://test-domain.com/start/#00000000-13d9-4d51-b282-e2be09de207f"},
438+
"Location": {"https://test-domain.com/start/#blabla-amaranth-smelt-9ba20cc1"},
439439
},
440-
Body: ("<a href=\"https://test-domain.com/start/#00000000-13d9-4d51-b282-e2be09de207f\">Found</a>.\n\n"),
440+
Body: ("<a href=\"https://test-domain.com/start/#blabla-amaranth-smelt-9ba20cc1\">Found</a>.\n\n"),
441441
},
442442
},
443443
{

components/ws-proxy/pkg/proxy/workspacerouter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const (
3131
// Used to communicate router error happening in the matcher with the error handler which set the code to the HTTP response
3232
routerErrorCode = "routerErrorCode"
3333

34-
workspaceIDRegex = "(?P<" + workspaceIDIdentifier + ">[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"
34+
workspaceIDRegex = "(?P<" + workspaceIDIdentifier + ">[a-z]+-[a-z]+-[a-z]+-[0-9a-f]{8})"
3535
workspacePortRegex = "(?P<" + workspacePortIdentifier + ">[0-9]+)-"
3636
)
3737

0 commit comments

Comments
 (0)