diff --git a/components/dashboard/src/user-settings/Integrations.tsx b/components/dashboard/src/user-settings/Integrations.tsx index aaadd3e9c9b720..415606cbab470c 100644 --- a/components/dashboard/src/user-settings/Integrations.tsx +++ b/components/dashboard/src/user-settings/Integrations.tsx @@ -4,10 +4,10 @@ * See License.AGPL.txt in the project root for license information. */ -import { getScopesForAuthProviderType } from "@gitpod/public-api-common/lib/auth-providers"; +import { getRequiredScopes, getScopesForAuthProviderType } from "@gitpod/public-api-common/lib/auth-providers"; import { SelectAccountPayload } from "@gitpod/gitpod-protocol/lib/auth"; import { useQuery } from "@tanstack/react-query"; -import React, { useCallback, useContext, useEffect, useMemo, useState } from "react"; +import { useCallback, useContext, useEffect, useMemo, useState } from "react"; import Alert from "../components/Alert"; import { CheckboxInputField, CheckboxListField } from "../components/forms/CheckboxInputField"; import ConfirmationModal from "../components/ConfirmationModal"; @@ -54,6 +54,46 @@ export default function Integrations() { ); } +const getDescriptionForScope = (scope: string) => { + switch (scope) { + // GitHub + case "user:email": + return "Read-only access to your email addresses"; + case "read:user": + return "Read-only access to your profile information"; + case "public_repo": + return "Write access to code in public repositories and organizations"; + case "repo": + return "Read/write access to code in private repositories and organizations"; + case "read:org": + return "Read-only access to organizations (used to suggest organizations when forking a repository)"; + case "workflow": + return "Allow updating GitHub Actions workflow files"; + // GitLab + case "read_user": + return "Read-only access to your email addresses"; + case "api": + return "Allow making API calls (used to set up a webhook when enabling prebuilds for a repository)"; + case "read_repository": + return "Read/write access to your repositories"; + // Bitbucket + case "account": + return "Read-only access to your account information"; + case "repository": + return "Read-only access to your repositories (note: Bitbucket doesn't support revoking scopes)"; + case "repository:write": + return "Read/write access to your repositories (note: Bitbucket doesn't support revoking scopes)"; + case "pullrequest": + return "Read access to pull requests and ability to collaborate via comments, tasks, and approvals (note: Bitbucket doesn't support revoking scopes)"; + case "pullrequest:write": + return "Allow creating, merging and declining pull requests (note: Bitbucket doesn't support revoking scopes)"; + case "webhook": + return "Allow installing webhooks (used when enabling prebuilds for a repository, note: Bitbucket doesn't support revoking scopes)"; + default: + return ""; + } +}; + function GitProviders() { const { user, setUser } = useContext(UserContext); @@ -250,45 +290,6 @@ function GitProviders() { setEditModal({ ...editModal, nextScopes }); }; - const getDescriptionForScope = (scope: string) => { - switch (scope) { - case "user:email": - return "Read-only access to your email addresses"; - case "read:user": - return "Read-only access to your profile information"; - case "public_repo": - return "Write access to code in public repositories and organizations"; - case "repo": - return "Read/write access to code in private repositories and organizations"; - case "read:org": - return "Read-only access to organizations (used to suggest organizations when forking a repository)"; - case "workflow": - return "Allow updating GitHub Actions workflow files"; - // GitLab - case "read_user": - return "Read-only access to your email addresses"; - case "api": - return "Allow making API calls (used to set up a webhook when enabling prebuilds for a repository)"; - case "read_repository": - return "Read/write access to your repositories"; - // Bitbucket - case "account": - return "Read-only access to your account information"; - case "repository": - return "Read-only access to your repositories (note: Bitbucket doesn't support revoking scopes)"; - case "repository:write": - return "Read/write access to your repositories (note: Bitbucket doesn't support revoking scopes)"; - case "pullrequest": - return "Read access to pull requests and ability to collaborate via comments, tasks, and approvals (note: Bitbucket doesn't support revoking scopes)"; - case "pullrequest:write": - return "Allow creating, merging and declining pull requests (note: Bitbucket doesn't support revoking scopes)"; - case "webhook": - return "Allow installing webhooks (used when enabling prebuilds for a repository, note: Bitbucket doesn't support revoking scopes)"; - default: - return ""; - } - }; - return (
{selectAccountModal && ( @@ -325,18 +326,22 @@ function GitProviders() { Edit Permissions - {(getScopesForAuthProviderType(editModal.provider.type) || []).map((scope) => ( - onChangeScopeHandler(checked, scope)} - /> - ))} + {(getScopesForAuthProviderType(editModal.provider.type) || []).map((scope) => { + const isRequired = getRequiredScopes(editModal.provider.type)?.default.includes(scope); + + return ( + onChangeScopeHandler(checked, scope)} + /> + ); + })} diff --git a/components/gitpod-db/src/typeorm/user-db-impl.ts b/components/gitpod-db/src/typeorm/user-db-impl.ts index 1ad4d5de466815..a59feac01eb4cf 100644 --- a/components/gitpod-db/src/typeorm/user-db-impl.ts +++ b/components/gitpod-db/src/typeorm/user-db-impl.ts @@ -571,7 +571,7 @@ export class TypeORMUserDBImpl extends TransactionalDBImpl implements Us accessTokenExpiresAt: expiry, client, user, - scopes: scopes, + scopes, }; } async issueRefreshToken(accessToken: OAuthToken): Promise { diff --git a/components/public-api/typescript-common/src/auth-providers.ts b/components/public-api/typescript-common/src/auth-providers.ts index 61d05d348dd7c0..1c573e17c00c2e 100644 --- a/components/public-api/typescript-common/src/auth-providers.ts +++ b/components/public-api/typescript-common/src/auth-providers.ts @@ -6,21 +6,25 @@ import { AuthProviderType } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb"; -export namespace GitLabScope { +export namespace GitLabOAuthScopes { export const READ_USER = "read_user"; export const API = "api"; export const READ_REPO = "read_repository"; export const ALL = [READ_USER, API, READ_REPO]; - /** - * Minimal required permission. - * GitLab API usage requires the permission of a user. - */ - export const DEFAULT = [READ_USER, API]; - export const REPO = [API, READ_REPO]; + + export const Requirements = { + /** + * Minimal required permission. + * GitLab API usage requires the permission of a user. + */ + DEFAULT: [READ_USER, API], + + REPO: [API, READ_REPO], + }; } -export namespace GitHubScope { +export namespace GitHubOAuthScopes { export const EMAIL = "user:email"; export const READ_USER = "read:user"; export const PUBLIC = "public_repo"; @@ -29,9 +33,17 @@ export namespace GitHubScope { export const WORKFLOW = "workflow"; export const ALL = [EMAIL, READ_USER, PUBLIC, PRIVATE, ORGS, WORKFLOW]; - export const DEFAULT = ALL; - export const PUBLIC_REPO = ALL; - export const PRIVATE_REPO = ALL; + + export const Requirements = { + /** + * Minimal required permission. + * GitHub's API is not restricted any further. + */ + DEFAULT: [EMAIL], + + PUBLIC_REPO: [PUBLIC], + PRIVATE_REPO: [PRIVATE], + }; } export namespace BitbucketOAuthScopes { @@ -48,15 +60,14 @@ export namespace BitbucketOAuthScopes { /** Create, comment and merge pull requests */ export const PULL_REQUEST_WRITE = "pullrequest:write"; - export const ALL = [ - ACCOUNT_READ, - REPOSITORY_READ, - REPOSITORY_WRITE, - PULL_REQUEST_READ, - PULL_REQUEST_WRITE, - ]; + export const ALL = [ACCOUNT_READ, REPOSITORY_READ, REPOSITORY_WRITE, PULL_REQUEST_READ, PULL_REQUEST_WRITE]; - export const DEFAULT = ALL; + export const Requirements = { + /** + * Minimal required permission. + */ + DEFAULT: ALL, + }; } export namespace BitbucketServerOAuthScopes { @@ -74,17 +85,22 @@ export namespace BitbucketServerOAuthScopes { export const ALL = [PUBLIC_REPOS, REPO_READ, REPO_WRITE, REPO_ADMIN, PROJECT_ADMIN]; - export const DEFAULT = ALL; + export const Requirements = { + /** + * Minimal required permission. + */ + DEFAULT: [PUBLIC_REPOS, REPO_READ, REPO_WRITE], + }; } export function getScopesForAuthProviderType(type: AuthProviderType | string) { switch (type) { case AuthProviderType.GITHUB: case "GitHub": - return GitHubScope.ALL; + return GitHubOAuthScopes.ALL; case AuthProviderType.GITLAB: case "GitLab": - return GitLabScope.ALL; + return GitLabOAuthScopes.ALL; case AuthProviderType.BITBUCKET: case "Bitbucket": return BitbucketOAuthScopes.ALL; @@ -99,30 +115,30 @@ export function getRequiredScopes(type: AuthProviderType | string) { case AuthProviderType.GITHUB: case "GitHub": return { - default: GitHubScope.DEFAULT, - publicRepo: GitHubScope.PUBLIC_REPO, - privateRepo: GitHubScope.PRIVATE_REPO, + default: GitHubOAuthScopes.Requirements.DEFAULT, + publicRepo: GitHubOAuthScopes.Requirements.PUBLIC_REPO, + privateRepo: GitHubOAuthScopes.Requirements.PRIVATE_REPO, }; case AuthProviderType.GITLAB: case "GitLab": return { - default: GitLabScope.DEFAULT, - publicRepo: GitLabScope.DEFAULT, - privateRepo: GitLabScope.REPO, + default: GitLabOAuthScopes.Requirements.DEFAULT, + publicRepo: GitLabOAuthScopes.Requirements.DEFAULT, + privateRepo: GitLabOAuthScopes.Requirements.REPO, }; case AuthProviderType.BITBUCKET: case "Bitbucket": return { - default: BitbucketOAuthScopes.DEFAULT, - publicRepo: BitbucketOAuthScopes.DEFAULT, - privateRepo: BitbucketOAuthScopes.DEFAULT, + default: BitbucketOAuthScopes.Requirements.DEFAULT, + publicRepo: BitbucketOAuthScopes.Requirements.DEFAULT, + privateRepo: BitbucketOAuthScopes.Requirements.DEFAULT, }; case AuthProviderType.BITBUCKET_SERVER: case "BitbucketServer": return { - default: BitbucketServerOAuthScopes.DEFAULT, - publicRepo: BitbucketServerOAuthScopes.DEFAULT, - privateRepo: BitbucketServerOAuthScopes.DEFAULT, + default: BitbucketServerOAuthScopes.Requirements.DEFAULT, + publicRepo: BitbucketServerOAuthScopes.Requirements.DEFAULT, + privateRepo: BitbucketServerOAuthScopes.Requirements.DEFAULT, }; } } diff --git a/components/server/src/auth/auth-provider-scopes.ts b/components/server/src/auth/auth-provider-scopes.ts deleted file mode 100644 index 95534e67717534..00000000000000 --- a/components/server/src/auth/auth-provider-scopes.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2023 Gitpod GmbH. All rights reserved. - * Licensed under the GNU Affero General Public License (AGPL). - * See License.AGPL.txt in the project root for license information. - */ - -import { GitHubScope } from "../github/scopes"; -import { GitLabScope } from "../gitlab/scopes"; -import { BitbucketOAuthScopes } from "../bitbucket/bitbucket-oauth-scopes"; -import { BitbucketServerOAuthScopes } from "../bitbucket-server/bitbucket-server-oauth-scopes"; - -export function getRequiredScopes(entry: { type: string }) { - switch (entry.type) { - case "GitHub": - return { - default: GitHubScope.Requirements.DEFAULT, - publicRepo: GitHubScope.Requirements.PUBLIC_REPO, - privateRepo: GitHubScope.Requirements.PRIVATE_REPO, - }; - case "GitLab": - return { - default: GitLabScope.Requirements.DEFAULT, - publicRepo: GitLabScope.Requirements.DEFAULT, - privateRepo: GitLabScope.Requirements.REPO, - }; - case "Bitbucket": - return { - default: BitbucketOAuthScopes.Requirements.DEFAULT, - publicRepo: BitbucketOAuthScopes.Requirements.DEFAULT, - privateRepo: BitbucketOAuthScopes.Requirements.DEFAULT, - }; - case "BitbucketServer": - return { - default: BitbucketServerOAuthScopes.Requirements.DEFAULT, - publicRepo: BitbucketServerOAuthScopes.Requirements.DEFAULT, - privateRepo: BitbucketServerOAuthScopes.Requirements.DEFAULT, - }; - } -} -export function getScopesOfProvider(entry: { type: string }) { - switch (entry.type) { - case "GitHub": - return GitHubScope.All; - case "GitLab": - return GitLabScope.All; - case "Bitbucket": - return BitbucketOAuthScopes.ALL; - case "BitbucketServer": - return BitbucketServerOAuthScopes.ALL; - } -} diff --git a/components/server/src/auth/auth-provider-service.ts b/components/server/src/auth/auth-provider-service.ts index 293e0ead3557c1..3d8f2c3a7a1902 100644 --- a/components/server/src/auth/auth-provider-service.ts +++ b/components/server/src/auth/auth-provider-service.ts @@ -18,7 +18,7 @@ import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; import fetch from "node-fetch"; import { Authorizer } from "../authorization/authorizer"; import { ApplicationError, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error"; -import { getRequiredScopes, getScopesOfProvider } from "./auth-provider-scopes"; +import { getRequiredScopes, getScopesForAuthProviderType } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class AuthProviderService { @@ -106,8 +106,8 @@ export class AuthProviderService { hiddenOnDashboard: ap.hiddenOnDashboard, disallowLogin: ap.disallowLogin, description: ap.description, - scopes: getScopesOfProvider(ap), - requirements: getRequiredScopes(ap), + scopes: getScopesForAuthProviderType(ap.type), + requirements: getRequiredScopes(ap.type), }; } diff --git a/components/server/src/auth/resource-access.ts b/components/server/src/auth/resource-access.ts index ba4c7ba60adc6c..526686e7d0fe46 100644 --- a/components/server/src/auth/resource-access.ts +++ b/components/server/src/auth/resource-access.ts @@ -23,8 +23,8 @@ import { UnauthorizedError } from "../errors"; import { RepoURL } from "../repohost"; import { HostContextProvider } from "./host-context-provider"; import { reportGuardAccessCheck } from "../prometheus-metrics"; -import { getRequiredScopes } from "./auth-provider-scopes"; import { FunctionAccessGuard } from "./function-access"; +import { getRequiredScopes } from "@gitpod/public-api-common/lib/auth-providers"; declare let resourceInstance: GuardedResource; export type GuardedResourceKind = typeof resourceInstance.kind; @@ -585,7 +585,7 @@ export class RepositoryResourceGuard implements ResourceAccessGuard { const identity = User.getIdentity(this.user, authProvider.authProviderId); if (!identity) { const providerType = authProvider.info.authProviderType; - const requiredScopes = getRequiredScopes({ type: providerType })?.default; + const requiredScopes = getRequiredScopes(providerType)?.default; throw UnauthorizedError.create({ host: repoUrl.host, repoName: repoUrl.repo, diff --git a/components/server/src/bitbucket-server/bitbucket-server-auth-provider.ts b/components/server/src/bitbucket-server/bitbucket-server-auth-provider.ts index c5cc61f60710ed..e1e759feb7e74a 100644 --- a/components/server/src/bitbucket-server/bitbucket-server-auth-provider.ts +++ b/components/server/src/bitbucket-server/bitbucket-server-auth-provider.ts @@ -10,8 +10,8 @@ import express from "express"; import { inject, injectable } from "inversify"; import { AuthUserSetup } from "../auth/auth-provider"; import { GenericAuthProvider } from "../auth/generic-auth-provider"; -import { BitbucketServerOAuthScopes } from "./bitbucket-server-oauth-scopes"; import { BitbucketServerApi } from "./bitbucket-server-api"; +import { BitbucketServerOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class BitbucketServerAuthProvider extends GenericAuthProvider { diff --git a/components/server/src/bitbucket-server/bitbucket-server-oauth-scopes.ts b/components/server/src/bitbucket-server/bitbucket-server-oauth-scopes.ts deleted file mode 100644 index 529f25d56289ca..00000000000000 --- a/components/server/src/bitbucket-server/bitbucket-server-oauth-scopes.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2021 Gitpod GmbH. All rights reserved. - * Licensed under the GNU Affero General Public License (AGPL). - * See License.AGPL.txt in the project root for license information. - */ - -// https://confluence.atlassian.com/bitbucketserver/bitbucket-oauth-2-0-provider-api-1108483661.html#BitbucketOAuth2.0providerAPI-scopesScopes - -export namespace BitbucketServerOAuthScopes { - /** View projects and repositories that are publicly accessible, including pulling code and cloning repositories. */ - export const PUBLIC_REPOS = "PUBLIC_REPOS"; - /** View projects and repositories the user account can view, including pulling code, cloning, and forking repositories. Create and comment on pull requests. */ - export const REPO_READ = "REPO_READ"; - /** Push over https, fork repo */ - export const REPO_WRITE = "REPO_WRITE"; - - export const REPO_ADMIN = "REPO_ADMIN"; - export const PROJECT_ADMIN = "PROJECT_ADMIN"; - - export const ALL = [PUBLIC_REPOS, REPO_READ, REPO_WRITE, REPO_ADMIN, PROJECT_ADMIN]; - - export const Requirements = { - /** - * Minimal required permission. - */ - DEFAULT: [PUBLIC_REPOS, REPO_READ, REPO_WRITE], - }; -} diff --git a/components/server/src/bitbucket-server/bitbucket-server-token-handler.ts b/components/server/src/bitbucket-server/bitbucket-server-token-handler.ts index bb1f728c9bb5e6..0cfd3857632a26 100644 --- a/components/server/src/bitbucket-server/bitbucket-server-token-handler.ts +++ b/components/server/src/bitbucket-server/bitbucket-server-token-handler.ts @@ -9,7 +9,7 @@ import { inject, injectable } from "inversify"; import { AuthProviderParams } from "../auth/auth-provider"; import { UnauthorizedError } from "../errors"; import { TokenProvider } from "../user/token-provider"; -import { BitbucketServerOAuthScopes } from "./bitbucket-server-oauth-scopes"; +import { BitbucketServerOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class BitbucketServerTokenHelper { diff --git a/components/server/src/bitbucket/bitbucket-auth-provider.ts b/components/server/src/bitbucket/bitbucket-auth-provider.ts index 937f801773f1c3..450f2fe3a19214 100644 --- a/components/server/src/bitbucket/bitbucket-auth-provider.ts +++ b/components/server/src/bitbucket/bitbucket-auth-provider.ts @@ -11,7 +11,7 @@ import express from "express"; import { injectable } from "inversify"; import { AuthUserSetup } from "../auth/auth-provider"; import { GenericAuthProvider } from "../auth/generic-auth-provider"; -import { BitbucketOAuthScopes } from "./bitbucket-oauth-scopes"; +import { BitbucketOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class BitbucketAuthProvider extends GenericAuthProvider { diff --git a/components/server/src/bitbucket/bitbucket-oauth-scopes.ts b/components/server/src/bitbucket/bitbucket-oauth-scopes.ts deleted file mode 100644 index b8795f2f120b44..00000000000000 --- a/components/server/src/bitbucket/bitbucket-oauth-scopes.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2020 Gitpod GmbH. All rights reserved. - * Licensed under the GNU Affero General Public License (AGPL). - * See License.AGPL.txt in the project root for license information. - */ - -// https://confluence.atlassian.com/bitbucket/oauth-on-bitbucket-cloud-238027431.html - -export namespace BitbucketOAuthScopes { - /** Read user info like name, e-mail addresses etc. */ - export const ACCOUNT_READ = "account"; - /** Access repo info, clone repo over https, read and write issues */ - export const REPOSITORY_READ = "repository"; - /** Push over https, fork repo */ - export const REPOSITORY_WRITE = "repository:write"; - /** Lists and read pull requests */ - export const PULL_REQUEST_READ = "pullrequest"; - /** Create, comment and merge pull requests */ - export const PULL_REQUEST_WRITE = "pullrequest:write"; - - export const ALL = [ACCOUNT_READ, REPOSITORY_READ, REPOSITORY_WRITE, PULL_REQUEST_READ, PULL_REQUEST_WRITE]; - - export const Requirements = { - /** - * Minimal required permission. - */ - DEFAULT: ALL, - }; -} diff --git a/components/server/src/bitbucket/bitbucket-token-handler.ts b/components/server/src/bitbucket/bitbucket-token-handler.ts index fdf9389eb79d73..533eac7979f769 100644 --- a/components/server/src/bitbucket/bitbucket-token-handler.ts +++ b/components/server/src/bitbucket/bitbucket-token-handler.ts @@ -9,7 +9,7 @@ import { inject, injectable } from "inversify"; import { AuthProviderParams } from "../auth/auth-provider"; import { UnauthorizedError } from "../errors"; import { TokenProvider } from "../user/token-provider"; -import { BitbucketOAuthScopes } from "./bitbucket-oauth-scopes"; +import { BitbucketOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class BitbucketTokenHelper { diff --git a/components/server/src/dev/dev-data.ts b/components/server/src/dev/dev-data.ts index 95360a56a14762..271b94684d6b37 100644 --- a/components/server/src/dev/dev-data.ts +++ b/components/server/src/dev/dev-data.ts @@ -5,8 +5,7 @@ */ import { IssueContext, User, PullRequestContext, Repository, Token } from "@gitpod/gitpod-protocol"; -import { GitHubScope } from "../github/scopes"; -import { GitLabScope } from "../gitlab/scopes"; +import { GitHubOAuthScopes, GitLabOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; export namespace DevData { export function createTestUser(): User { @@ -41,7 +40,7 @@ export namespace DevData { export function createGitHubTestToken(): Token { return { ...getTokenFromEnv("GITPOD_TEST_TOKEN_GITHUB"), - scopes: [GitHubScope.EMAIL, GitHubScope.PUBLIC, GitHubScope.PRIVATE], + scopes: [GitHubOAuthScopes.EMAIL, GitHubOAuthScopes.PUBLIC, GitHubOAuthScopes.PRIVATE], }; } @@ -61,7 +60,7 @@ export namespace DevData { export function createGitlabTestToken(): Token { return { ...getTokenFromEnv("GITPOD_TEST_TOKEN_GITLAB"), - scopes: [GitLabScope.READ_USER, GitLabScope.API], + scopes: [GitLabOAuthScopes.READ_USER, GitLabOAuthScopes.API], }; } diff --git a/components/server/src/github/api.ts b/components/server/src/github/api.ts index 7899c9a119dc60..c7593a1d6a6ff5 100644 --- a/components/server/src/github/api.ts +++ b/components/server/src/github/api.ts @@ -13,12 +13,12 @@ import { Branch, CommitInfo, User } from "@gitpod/gitpod-protocol"; import { GarbageCollectedCache } from "@gitpod/gitpod-protocol/lib/util/garbage-collected-cache"; import { injectable, inject } from "inversify"; import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; -import { GitHubScope } from "./scopes"; import { AuthProviderParams } from "../auth/auth-provider"; import { GitHubTokenHelper } from "./github-token-helper"; import { Deferred } from "@gitpod/gitpod-protocol/lib/util/deferred"; import { URL } from "url"; +import { GitHubOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; export class GitHubApiError extends Error { readonly code: number; @@ -149,7 +149,7 @@ export class GitHubRestApi { } else { const githubToken = await this.tokenHelper.getTokenWithScopes( userOrToken, - GitHubScope.Requirements.DEFAULT, + GitHubOAuthScopes.Requirements.DEFAULT, ); token = githubToken.value; } diff --git a/components/server/src/github/github-auth-provider.ts b/components/server/src/github/github-auth-provider.ts index 2c810abff0a73d..03eaa82eb620d6 100644 --- a/components/server/src/github/github-auth-provider.ts +++ b/components/server/src/github/github-auth-provider.ts @@ -8,23 +8,23 @@ import { injectable } from "inversify"; import express from "express"; import { AuthProviderInfo } from "@gitpod/gitpod-protocol"; import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; -import { GitHubScope } from "./scopes"; import { AuthUserSetup } from "../auth/auth-provider"; import { Octokit } from "@octokit/rest"; import { GitHubApiError } from "./api"; import { GenericAuthProvider } from "../auth/generic-auth-provider"; import { oauthUrls } from "./github-urls"; +import { GitHubOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class GitHubAuthProvider extends GenericAuthProvider { get info(): AuthProviderInfo { return { ...this.defaultInfo(), - scopes: GitHubScope.All, + scopes: GitHubOAuthScopes.ALL, requirements: { - default: GitHubScope.Requirements.DEFAULT, - publicRepo: GitHubScope.Requirements.PUBLIC_REPO, - privateRepo: GitHubScope.Requirements.PRIVATE_REPO, + default: GitHubOAuthScopes.Requirements.DEFAULT, + publicRepo: GitHubOAuthScopes.Requirements.PUBLIC_REPO, + privateRepo: GitHubOAuthScopes.Requirements.PRIVATE_REPO, }, }; } @@ -40,7 +40,7 @@ export class GitHubAuthProvider extends GenericAuthProvider { ...oauth!, authorizationUrl: oauth.authorizationUrl || defaultUrls.authorizationUrl, tokenUrl: oauth.tokenUrl || defaultUrls.tokenUrl, - scope: GitHubScope.All.join(scopeSeparator), + scope: GitHubOAuthScopes.ALL.join(scopeSeparator), scopeSeparator, }; } @@ -52,7 +52,7 @@ export class GitHubAuthProvider extends GenericAuthProvider { state: string, scope?: string[], ) { - super.authorize(req, res, next, state, scope ? scope : GitHubScope.Requirements.DEFAULT); + super.authorize(req, res, next, state, scope ? scope : GitHubOAuthScopes.Requirements.DEFAULT); } /** diff --git a/components/server/src/github/github-context-parser.ts b/components/server/src/github/github-context-parser.ts index ee067825459526..fc5c33d89e7d13 100644 --- a/components/server/src/github/github-context-parser.ts +++ b/components/server/src/github/github-context-parser.ts @@ -19,12 +19,12 @@ import { GitHubGraphQlEndpoint, QueryResult } from "./api"; import { NotFoundError, UnauthorizedError } from "../errors"; import { log, LogContext, LogPayload } from "@gitpod/gitpod-protocol/lib/util/logging"; import { IContextParser, IssueContexts, AbstractContextParser } from "../workspace/context-parser"; -import { GitHubScope } from "./scopes"; import { GitHubTokenHelper } from "./github-token-helper"; import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing"; import { RepoURL } from "../repohost"; import { containsScopes } from "../prebuilds/token-scopes-inclusion"; import { TrustedValue } from "@gitpod/gitpod-protocol/lib/util/scrubbing"; +import { GitHubOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class GithubContextParser extends AbstractContextParser implements IContextParser { @@ -95,10 +95,10 @@ export class GithubContextParser extends AbstractContextParser implements IConte throw UnauthorizedError.create({ host: this.config.host, providerType: "GitHub", - requiredScopes: GitHubScope.Requirements.PUBLIC_REPO, + requiredScopes: GitHubOAuthScopes.Requirements.PUBLIC_REPO, repoName: RepoURL.parseRepoUrl(contextUrl)?.repo, providerIsConnected: !!token, - isMissingScopes: containsScopes(token?.scopes, GitHubScope.Requirements.PUBLIC_REPO), + isMissingScopes: containsScopes(token?.scopes, GitHubOAuthScopes.Requirements.PUBLIC_REPO), }); } throw error; diff --git a/components/server/src/github/github-token-helper.ts b/components/server/src/github/github-token-helper.ts index a7f4ed8d14c96d..3b1302e3294f77 100644 --- a/components/server/src/github/github-token-helper.ts +++ b/components/server/src/github/github-token-helper.ts @@ -8,8 +8,8 @@ import { injectable, inject } from "inversify"; import { AuthProviderParams } from "../auth/auth-provider"; import { User, Token } from "@gitpod/gitpod-protocol"; import { UnauthorizedError } from "../errors"; -import { GitHubScope } from "./scopes"; import { TokenProvider } from "../user/token-provider"; +import { GitHubOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class GitHubTokenHelper { @@ -37,12 +37,12 @@ export class GitHubTokenHelper { // no token } if (requiredScopes.length === 0) { - requiredScopes = GitHubScope.Requirements.DEFAULT; + requiredScopes = GitHubOAuthScopes.Requirements.DEFAULT; } throw UnauthorizedError.create({ host, providerType: "GitHub", - requiredScopes: GitHubScope.Requirements.DEFAULT, + requiredScopes: GitHubOAuthScopes.Requirements.DEFAULT, providerIsConnected: false, isMissingScopes: true, }); @@ -50,8 +50,8 @@ export class GitHubTokenHelper { protected containsScopes(token: Token, wantedScopes: string[] | undefined): boolean { const wantedSet = new Set(wantedScopes); const currentScopes = [...token.scopes]; - if (currentScopes.some((s) => s === GitHubScope.PRIVATE)) { - currentScopes.push(GitHubScope.PUBLIC); // normalize private_repo, which includes public_repo + if (currentScopes.some((s) => s === GitHubOAuthScopes.PRIVATE)) { + currentScopes.push(GitHubOAuthScopes.PUBLIC); // normalize private_repo, which includes public_repo } currentScopes.forEach((s) => wantedSet.delete(s)); return wantedSet.size === 0; diff --git a/components/server/src/github/scopes.ts b/components/server/src/github/scopes.ts deleted file mode 100644 index 64575aa36215eb..00000000000000 --- a/components/server/src/github/scopes.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2020 Gitpod GmbH. All rights reserved. - * Licensed under the GNU Affero General Public License (AGPL). - * See License.AGPL.txt in the project root for license information. - */ - -export namespace GitHubScope { - export const EMAIL = "user:email"; - export const READ_USER = "read:user"; - export const PUBLIC = "public_repo"; - export const PRIVATE = "repo"; - export const ORGS = "read:org"; - export const WORKFLOW = "workflow"; - - export const All = [EMAIL, READ_USER, PUBLIC, PRIVATE, ORGS, WORKFLOW]; - export const Requirements = { - /** - * Minimal required permission. - * GitHub's API is not restricted any further. - */ - DEFAULT: [EMAIL], - - PUBLIC_REPO: [PUBLIC], - PRIVATE_REPO: [PRIVATE], - }; -} diff --git a/components/server/src/gitlab/api.ts b/components/server/src/gitlab/api.ts index 635f361f4a66c2..301a8918ca1dc2 100644 --- a/components/server/src/gitlab/api.ts +++ b/components/server/src/gitlab/api.ts @@ -26,9 +26,9 @@ import { SimpleProjectSchema, } from "@gitbeaker/core"; import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; -import { GitLabScope } from "./scopes"; import { AuthProviderParams } from "../auth/auth-provider"; import { GitLabTokenHelper } from "./gitlab-token-helper"; +import { GitLabOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class GitLabApi { @@ -42,7 +42,7 @@ export class GitLabApi { } else { const gitlabToken = await this.tokenHelper.getTokenWithScopes( userOrToken, - GitLabScope.Requirements.DEFAULT, + GitLabOAuthScopes.Requirements.DEFAULT, ); oauthToken = gitlabToken.value; } diff --git a/components/server/src/gitlab/gitlab-auth-provider.ts b/components/server/src/gitlab/gitlab-auth-provider.ts index 9ee945da460b3f..e9475c0f69b3ca 100644 --- a/components/server/src/gitlab/gitlab-auth-provider.ts +++ b/components/server/src/gitlab/gitlab-auth-provider.ts @@ -8,23 +8,23 @@ import express from "express"; import { injectable } from "inversify"; import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; import { AuthProviderInfo } from "@gitpod/gitpod-protocol"; -import { GitLabScope } from "./scopes"; import { UnconfirmedUserException } from "../auth/errors"; import { GitLab } from "./api"; import { GenericAuthProvider } from "../auth/generic-auth-provider"; import { AuthUserSetup } from "../auth/auth-provider"; import { oauthUrls } from "./gitlab-urls"; +import { GitLabOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class GitLabAuthProvider extends GenericAuthProvider { get info(): AuthProviderInfo { return { ...this.defaultInfo(), - scopes: GitLabScope.All, + scopes: GitLabOAuthScopes.ALL, requirements: { - default: GitLabScope.Requirements.DEFAULT, - publicRepo: GitLabScope.Requirements.REPO, - privateRepo: GitLabScope.Requirements.REPO, + default: GitLabOAuthScopes.Requirements.DEFAULT, + publicRepo: GitLabOAuthScopes.Requirements.REPO, + privateRepo: GitLabOAuthScopes.Requirements.REPO, }, }; } @@ -41,7 +41,7 @@ export class GitLabAuthProvider extends GenericAuthProvider { authorizationUrl: oauth.authorizationUrl || defaultUrls.authorizationUrl, tokenUrl: oauth.tokenUrl || defaultUrls.tokenUrl, settingsUrl: oauth.settingsUrl || defaultUrls.settingsUrl, - scope: GitLabScope.All.join(scopeSeparator), + scope: GitLabOAuthScopes.ALL.join(scopeSeparator), scopeSeparator, }; } @@ -53,7 +53,7 @@ export class GitLabAuthProvider extends GenericAuthProvider { state: string, scope?: string[], ) { - super.authorize(req, res, next, state, scope ? scope : GitLabScope.Requirements.DEFAULT); + super.authorize(req, res, next, state, scope ? scope : GitLabOAuthScopes.Requirements.DEFAULT); } protected get baseURL() { diff --git a/components/server/src/gitlab/gitlab-context-parser.ts b/components/server/src/gitlab/gitlab-context-parser.ts index 44b47ffac1ab9b..17ac2e539485e9 100644 --- a/components/server/src/gitlab/gitlab-context-parser.ts +++ b/components/server/src/gitlab/gitlab-context-parser.ts @@ -17,7 +17,7 @@ import { } from "@gitpod/gitpod-protocol"; import { GitLabApi, GitLab } from "./api"; import { UnauthorizedError, NotFoundError } from "../errors"; -import { GitLabScope } from "./scopes"; +import { GitLabOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; import { IContextParser, IssueContexts, AbstractContextParser, URLParts } from "../workspace/context-parser"; import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; import { GitLabTokenHelper } from "./gitlab-token-helper"; @@ -74,10 +74,10 @@ export class GitlabContextParser extends AbstractContextParser implements IConte throw UnauthorizedError.create({ host: this.config.host, providerType: "Gitlab", - requiredScopes: GitLabScope.Requirements.DEFAULT, + requiredScopes: GitLabOAuthScopes.Requirements.DEFAULT, repoName: RepoURL.parseRepoUrl(contextUrl)?.repo, providerIsConnected: !!token, - isMissingScopes: containsScopes(token?.scopes, GitLabScope.Requirements.DEFAULT), + isMissingScopes: containsScopes(token?.scopes, GitLabOAuthScopes.Requirements.DEFAULT), }); } throw error; diff --git a/components/server/src/gitlab/gitlab-token-helper.ts b/components/server/src/gitlab/gitlab-token-helper.ts index 724cc60ff972d2..1d7905146f8410 100644 --- a/components/server/src/gitlab/gitlab-token-helper.ts +++ b/components/server/src/gitlab/gitlab-token-helper.ts @@ -8,8 +8,8 @@ import { User, Token } from "@gitpod/gitpod-protocol"; import { UnauthorizedError } from "../errors"; import { AuthProviderParams } from "../auth/auth-provider"; import { injectable, inject } from "inversify"; -import { GitLabScope } from "./scopes"; import { TokenProvider } from "../user/token-provider"; +import { GitLabOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; @injectable() export class GitLabTokenHelper { @@ -37,12 +37,12 @@ export class GitLabTokenHelper { console.error(e); } if (requiredScopes.length === 0) { - requiredScopes = GitLabScope.Requirements.DEFAULT; + requiredScopes = GitLabOAuthScopes.Requirements.DEFAULT; } throw UnauthorizedError.create({ host, providerType: "GitLab", - requiredScopes: GitLabScope.Requirements.DEFAULT, + requiredScopes: GitLabOAuthScopes.Requirements.DEFAULT, providerIsConnected: false, isMissingScopes: true, }); diff --git a/components/server/src/gitlab/scopes.ts b/components/server/src/gitlab/scopes.ts deleted file mode 100644 index ecfcae8dea3f78..00000000000000 --- a/components/server/src/gitlab/scopes.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2020 Gitpod GmbH. All rights reserved. - * Licensed under the GNU Affero General Public License (AGPL). - * See License.AGPL.txt in the project root for license information. - */ - -export namespace GitLabScope { - export const READ_USER = "read_user"; - export const API = "api"; - export const READ_REPO = "read_repository"; - - export const All = [READ_USER, API, READ_REPO]; - export const Requirements = { - /** - * Minimal required permission. - * GitLab API usage requires the permission of a user. - */ - DEFAULT: [READ_USER, API], - - REPO: [API, READ_REPO], - }; -} diff --git a/components/server/src/test/service-testing-container-module.ts b/components/server/src/test/service-testing-container-module.ts index f0b682b4da4512..21702d726623bd 100644 --- a/components/server/src/test/service-testing-container-module.ts +++ b/components/server/src/test/service-testing-container-module.ts @@ -34,13 +34,13 @@ import { } from "@gitpod/image-builder/lib"; import { IWorkspaceManagerClient, StartWorkspaceResponse } from "@gitpod/ws-manager/lib"; import { TokenProvider } from "../user/token-provider"; -import { GitHubScope } from "../github/scopes"; import { GitpodHostUrl } from "@gitpod/gitpod-protocol/lib/util/gitpod-host-url"; import * as crypto from "crypto"; import { ApplicationError, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error"; import { Subject, SubjectId } from "../auth/subject-id"; import { User } from "@gitpod/gitpod-protocol"; import { runWithRequestContext } from "../util/request-context"; +import { GitHubOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; const signingKeyPair = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 }); const validatingKeyPair1 = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 }); @@ -126,7 +126,7 @@ const mockApplyingContainerModule = new ContainerModule((bind, unbound, isbound, } return { value: "test", - scopes: [GitHubScope.EMAIL, GitHubScope.PUBLIC, GitHubScope.PRIVATE], + scopes: [GitHubOAuthScopes.EMAIL, GitHubOAuthScopes.PUBLIC, GitHubOAuthScopes.PRIVATE], }; }, });