From dba27877af09312c279db949e67b74a1872e944a Mon Sep 17 00:00:00 2001 From: "Cornelius A. Ludmann" Date: Tue, 13 Jul 2021 12:23:47 +0000 Subject: [PATCH 1/3] Revert "[gitpod-db] Fix migration timestamp for IdentityTokensToEmails" This reverts commit 14c36e65564ddde857cacf673f965ad67edd59c2. --- ...okensToEmails.ts => 1624290876856-IdentityTokensToEmails.ts} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename components/gitpod-db/src/typeorm/migration/{1625759714856-IdentityTokensToEmails.ts => 1624290876856-IdentityTokensToEmails.ts} (90%) diff --git a/components/gitpod-db/src/typeorm/migration/1625759714856-IdentityTokensToEmails.ts b/components/gitpod-db/src/typeorm/migration/1624290876856-IdentityTokensToEmails.ts similarity index 90% rename from components/gitpod-db/src/typeorm/migration/1625759714856-IdentityTokensToEmails.ts rename to components/gitpod-db/src/typeorm/migration/1624290876856-IdentityTokensToEmails.ts index 41fd89d2f5b8c9..34666824bcf3b8 100644 --- a/components/gitpod-db/src/typeorm/migration/1625759714856-IdentityTokensToEmails.ts +++ b/components/gitpod-db/src/typeorm/migration/1624290876856-IdentityTokensToEmails.ts @@ -6,7 +6,7 @@ import { MigrationInterface, QueryRunner } from "typeorm"; -export class IdentityTokensToEmails1625759714856 implements MigrationInterface { +export class IdentityTokensToEmails1624290876856 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { await queryRunner.renameColumn("d_b_identity", "tokens", "additionalEmails"); From aafd37088bd83d68c5691729e1c91acca725a65b Mon Sep 17 00:00:00 2001 From: "Cornelius A. Ludmann" Date: Tue, 13 Jul 2021 12:24:34 +0000 Subject: [PATCH 2/3] Revert "[typeorm] Catch JSON error in SIMPLE_JSON transformer" This reverts commit 1e78c6c96e6d5c6367ba4f7a6ab73d6e9a389cde. --- components/gitpod-db/src/typeorm/transformer.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/components/gitpod-db/src/typeorm/transformer.ts b/components/gitpod-db/src/typeorm/transformer.ts index 8d1f78e62d72a1..68a74d3cb98b63 100644 --- a/components/gitpod-db/src/typeorm/transformer.ts +++ b/components/gitpod-db/src/typeorm/transformer.ts @@ -6,7 +6,6 @@ import { ValueTransformer } from "typeorm/decorator/options/ValueTransformer"; import { EncryptionService } from "@gitpod/gitpod-protocol/lib/encryption/encryption-service"; -import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; export namespace Transformer { @@ -46,12 +45,7 @@ export namespace Transformer { return JSON.stringify(value || defaultValue); }, from(value: any): any { - try { - return typeof value === 'object' ? value : JSON.parse(value); - } catch (e) { - log.error(`Cannot parse JSON during TypeORM transformation. Returning default value '${JSON.stringify(defaultValue)}' instead. Value: ${JSON.stringify(value)}`, e); - return defaultValue; - } + return JSON.parse(value); } }; } From 7ed69186811b4a9f772adeedda9716e84017e67c Mon Sep 17 00:00:00 2001 From: "Cornelius A. Ludmann" Date: Tue, 13 Jul 2021 12:26:13 +0000 Subject: [PATCH 3/3] Revert "[server] support separate commit email" This reverts commit e59e14df235c3d957bbd69ccf72b619109b04990. --- CHANGELOG.md | 1 - .../src/accounting/account-service.spec.db.ts | 1 + .../src/typeorm/entity/db-identity.ts | 28 ++++++++----------- .../1624290876856-IdentityTokensToEmails.ts | 18 ------------ .../gitpod-db/src/typeorm/user-db-impl.ts | 3 +- components/gitpod-protocol/src/protocol.ts | 25 +++-------------- components/server/src/auth/auth-provider.ts | 3 +- .../server/src/github/github-auth-provider.ts | 24 +++++++++------- components/server/src/gitlab/api.ts | 1 - .../server/src/gitlab/gitlab-auth-provider.ts | 7 ++--- components/server/src/user/user-service.ts | 3 +- .../src/workspace/gitpod-server-impl.ts | 2 ++ .../server/src/workspace/workspace-starter.ts | 4 +-- 13 files changed, 42 insertions(+), 78 deletions(-) delete mode 100644 components/gitpod-db/src/typeorm/migration/1624290876856-IdentityTokensToEmails.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b2e1050ff12771..2563eb71d94218 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,6 @@ All notable changes to this project will be documented in this file. ## July 2021 - Fix `image.context` in `.gitpod.yml` ([#4715](https://github.com/gitpod-io/gitpod/pull/4715)) -- Support custom commit email address for GitHub and GitLab (keep email private). Thanks to [@philschatz](https://github.com/philschatz) for the contribution! ([#4115](https://github.com/gitpod-io/gitpod/pull/4115)) ## June 2021 diff --git a/components/ee/payment-endpoint/src/accounting/account-service.spec.db.ts b/components/ee/payment-endpoint/src/accounting/account-service.spec.db.ts index b5bfa6843c4916..b3b71e1191e023 100644 --- a/components/ee/payment-endpoint/src/accounting/account-service.spec.db.ts +++ b/components/ee/payment-endpoint/src/accounting/account-service.spec.db.ts @@ -72,6 +72,7 @@ const end = new Date(Date.UTC(2000, 2, 1)).toISOString(); authProviderId: 'github.com', authId: 'Sven', authName: 'Sven', + tokens: [] }] }); await this.workspaceDb.store({ diff --git a/components/gitpod-db/src/typeorm/entity/db-identity.ts b/components/gitpod-db/src/typeorm/entity/db-identity.ts index 70777a190339b0..d962274ee5ec7d 100644 --- a/components/gitpod-db/src/typeorm/entity/db-identity.ts +++ b/components/gitpod-db/src/typeorm/entity/db-identity.ts @@ -6,7 +6,7 @@ import { Entity, Column, PrimaryColumn, ManyToOne, Index } from "typeorm"; -import { Identity, Email } from "@gitpod/gitpod-protocol"; +import { Identity, Token } from "@gitpod/gitpod-protocol"; import { DBUser } from "./db-user"; import { Transformer } from "../transformer"; @@ -33,24 +33,20 @@ export class DBIdentity implements Identity { }) primaryEmail?: string; + /** @deprecated */ @Column({ - type: 'simple-json', - transformer: Transformer.compose( - { - to(value: any): any { - return value; - }, - from(value: any): Email[] { - // We reused the 'tokens' database field. Ignore old values - // in the DB and replace them with an empty array. - return Email.isEmailArray(value) ? value : []; - } + type: "simple-json", + // We want to deprecate the field without changing the schema just yet so we silence all writes and reads + transformer: { + to(value: any): any { + return []; }, - Transformer.SIMPLE_JSON([]) - ), - nullable: false, + from(value: any): any { + return []; + } + } }) - additionalEmails?: Email[]; + tokens: Token[]; @Column() deleted?: boolean; diff --git a/components/gitpod-db/src/typeorm/migration/1624290876856-IdentityTokensToEmails.ts b/components/gitpod-db/src/typeorm/migration/1624290876856-IdentityTokensToEmails.ts deleted file mode 100644 index 34666824bcf3b8..00000000000000 --- a/components/gitpod-db/src/typeorm/migration/1624290876856-IdentityTokensToEmails.ts +++ /dev/null @@ -1,18 +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. - */ - -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class IdentityTokensToEmails1624290876856 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.renameColumn("d_b_identity", "tokens", "additionalEmails"); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.renameColumn("d_b_identity", "additionalEmails", "tokens"); - } -} diff --git a/components/gitpod-db/src/typeorm/user-db-impl.ts b/components/gitpod-db/src/typeorm/user-db-impl.ts index 942d0b6d7fa6d2..357ea2f76eeb8a 100644 --- a/components/gitpod-db/src/typeorm/user-db-impl.ts +++ b/components/gitpod-db/src/typeorm/user-db-impl.ts @@ -289,7 +289,8 @@ export class TypeORMUserDBImpl implements UserDB { const dbUser = user as DBUser; // Here we need to fill the pseudo column 'user' in DBIdentity (see there for details) dbUser.identities.forEach(id => id.user = dbUser); - dbUser.identities.forEach(id => id.additionalEmails = id.additionalEmails || []); + // TODO deprecated: Remove once we delete that column + dbUser.identities.forEach(id => id.tokens = []); return dbUser; } diff --git a/components/gitpod-protocol/src/protocol.ts b/components/gitpod-protocol/src/protocol.ts index 14bbc033289f60..1d5d00cdf2ba60 100644 --- a/components/gitpod-protocol/src/protocol.ts +++ b/components/gitpod-protocol/src/protocol.ts @@ -60,6 +60,8 @@ export namespace User { const res = { ...user }; delete (res.additionalData); res.identities = res.identities.map(i => { + delete (i.tokens); + // The user field is not in the Identity shape, but actually exists on DBIdentity. // Trying to push this object out via JSON RPC will fail because of the cyclic nature // of this field. @@ -301,7 +303,8 @@ export interface Identity { authId: string; authName: string; primaryEmail?: string; - additionalEmails?: Email[]; + /** @deprecated */ + tokens?: Token[]; /** This is a flag that triggers the HARD DELETION of this entity */ deleted?: boolean; // readonly identities cannot be modified by the user @@ -322,26 +325,6 @@ export namespace Identity { } } -export enum EmailType { - COMMIT = 'commit', - OTHER = 'other' -} - -export interface Email { - address: string; - type: EmailType; -} - -export namespace Email { - export function is(data: any): data is Email { - return data.hasOwnProperty('address') - && data.hasOwnProperty('type'); - } - export function isEmailArray(data: any): data is Email[] { - return Array.isArray(data) && data.every(x => Email.is(x)); - } -} - export interface Token { value: string; scopes: string[]; diff --git a/components/server/src/auth/auth-provider.ts b/components/server/src/auth/auth-provider.ts index e398bb672eb94e..f0518d5c86da11 100644 --- a/components/server/src/auth/auth-provider.ts +++ b/components/server/src/auth/auth-provider.ts @@ -6,7 +6,7 @@ import * as express from 'express'; -import { AuthProviderInfo, User, OAuth2Config, AuthProviderEntry, Email } from "@gitpod/gitpod-protocol"; +import { AuthProviderInfo, User, OAuth2Config, AuthProviderEntry } from "@gitpod/gitpod-protocol"; import { saveSession } from '../express-util'; import { UserEnvVarValue } from "@gitpod/gitpod-protocol"; @@ -65,7 +65,6 @@ export interface AuthUser { readonly authId: string; readonly authName: string; readonly primaryEmail: string; - readonly additionalEmails?: Email[]; readonly name?: string; readonly avatarUrl?: string; } diff --git a/components/server/src/github/github-auth-provider.ts b/components/server/src/github/github-auth-provider.ts index 3e806fd54d48e7..3be85c1d19a160 100644 --- a/components/server/src/github/github-auth-provider.ts +++ b/components/server/src/github/github-auth-provider.ts @@ -6,7 +6,7 @@ import { injectable } from 'inversify'; import * as express from "express" -import { AuthProviderInfo, EmailType } from '@gitpod/gitpod-protocol'; +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"; @@ -98,13 +98,18 @@ export class GitHubAuthProvider extends GenericAuthProvider { .map((s: string) => s.trim()) ); - const primary = userEmails.filter(e => e.primary)[0]!; - const proxy = userEmails.find(e => e.email.endsWith(`@users.noreply.${this.config.host}`)); - - const additionalEmails = userEmails.filter(e => !e.primary && e.verified && e.visibility !== 'private').map(e => ({address: e.email, type: EmailType.OTHER})) - if (primary.visibility === 'private' && proxy) { - additionalEmails.push({ address: proxy.email, type: EmailType.COMMIT }); - } + const filterPrimaryEmail = (emails: typeof userEmails) => { + if (this.env.blockNewUsers) { + // if there is any verified email with a domain that is in the blockNewUsersPassList then use this email as primary email + const emailDomainInPasslist = (mail: string) => this.env.blockNewUsersPassList.some(e => mail.endsWith(`@${e}`)); + const result = emails.filter(e => e.verified).filter(e => emailDomainInPasslist(e.email)) + if (result.length > 0) { + return result[0].email; + } + } + // otherwise use GitHub's primary email as Gitpod's primary email + return emails.filter(e => e.primary)[0].email; + }; return { authUser: { @@ -112,8 +117,7 @@ export class GitHubAuthProvider extends GenericAuthProvider { authName: login, avatarUrl: avatar_url, name, - primaryEmail: primary.email, - additionalEmails, + primaryEmail: filterPrimaryEmail(userEmails) }, currentScopes } diff --git a/components/server/src/gitlab/api.ts b/components/server/src/gitlab/api.ts index ae214b6cbf5649..4844d3db527c92 100644 --- a/components/server/src/gitlab/api.ts +++ b/components/server/src/gitlab/api.ts @@ -199,7 +199,6 @@ export namespace GitLab { // https://docs.gitlab.com/ee/api/users.html#list-current-user-for-normal-users export interface User extends UserSchemaDefault { email: string; - commit_email?: string; state: "active" | string; confirmed_at: string | undefined, private_profile: boolean; diff --git a/components/server/src/gitlab/gitlab-auth-provider.ts b/components/server/src/gitlab/gitlab-auth-provider.ts index f94d87fb1b4dcc..31fd2f8f4cce92 100644 --- a/components/server/src/gitlab/gitlab-auth-provider.ts +++ b/components/server/src/gitlab/gitlab-auth-provider.ts @@ -7,7 +7,7 @@ import * as express from "express"; import { injectable } from 'inversify'; import { log } from '@gitpod/gitpod-protocol/lib/util/logging'; -import { AuthProviderInfo, EmailType } from '@gitpod/gitpod-protocol'; +import { AuthProviderInfo } from '@gitpod/gitpod-protocol'; import { GitLabScope } from "./scopes"; import { UnconfirmedUserException } from "../auth/errors"; import { GitLab } from "./api"; @@ -73,7 +73,7 @@ export class GitLabAuthProvider extends GenericAuthProvider { throw UnconfirmedUserException.create(unconfirmedUserMessage, result); } } - const { id, username, avatar_url, name, email, commit_email } = result; + const { id, username, avatar_url, name, email } = result; return { authUser: { @@ -81,8 +81,7 @@ export class GitLabAuthProvider extends GenericAuthProvider { authName: username, avatarUrl: avatar_url || undefined, name, - primaryEmail: email, - additionalEmails: commit_email ? [{ "address": commit_email, "type": EmailType.COMMIT }] : [], + primaryEmail: email }, currentScopes: this.readScopesFromVerifyParams(tokenResponse) } diff --git a/components/server/src/user/user-service.ts b/components/server/src/user/user-service.ts index 56c958280e332a..78cc32232dbb41 100644 --- a/components/server/src/user/user-service.ts +++ b/components/server/src/user/user-service.ts @@ -140,8 +140,7 @@ export class UserService { protected handleNewUser(newUser: User, isFirstUser: boolean) { if (this.env.blockNewUsers) { const emailDomainInPasslist = (mail: string) => this.env.blockNewUsersPassList.some(e => mail.endsWith(`@${e}`)); - const canPass = newUser.identities.some(i => (!!i.primaryEmail && emailDomainInPasslist(i.primaryEmail)) || - i.additionalEmails?.some(e => emailDomainInPasslist(e.address))); + const canPass = newUser.identities.some(i => !!i.primaryEmail && emailDomainInPasslist(i.primaryEmail)); newUser.blocked = !canPass; } diff --git a/components/server/src/workspace/gitpod-server-impl.ts b/components/server/src/workspace/gitpod-server-impl.ts index 854dfcb6db6815..0c46faf64cd069 100644 --- a/components/server/src/workspace/gitpod-server-impl.ts +++ b/components/server/src/workspace/gitpod-server-impl.ts @@ -1660,6 +1660,8 @@ export class GitpodServerImpl { + delete (i.tokens); + // The user field is not in the Identity shape, but actually exists on DBIdentity. // Trying to push this object out via JSON RPC will fail because of the cyclic nature // of this field. diff --git a/components/server/src/workspace/workspace-starter.ts b/components/server/src/workspace/workspace-starter.ts index cc54bbb9bae271..eaff88f4460868 100644 --- a/components/server/src/workspace/workspace-starter.ts +++ b/components/server/src/workspace/workspace-starter.ts @@ -7,7 +7,7 @@ import { CloneTargetMode, FileDownloadInitializer, GitAuthMethod, GitConfig, GitInitializer, PrebuildInitializer, SnapshotInitializer, WorkspaceInitializer } from "@gitpod/content-service/lib"; import { CompositeInitializer, FromBackupInitializer } from "@gitpod/content-service/lib/initializer_pb"; import { DBUser, DBWithTracing, TracedUserDB, TracedWorkspaceDB, UserDB, WorkspaceDB } from '@gitpod/gitpod-db/lib'; -import { CommitContext, Disposable, GitpodToken, GitpodTokenType, IssueContext, NamedWorkspaceFeatureFlag, PullRequestContext, RefType, SnapshotContext, StartWorkspaceResult, User, UserEnvVar, UserEnvVarValue, WithEnvvarsContext, WithPrebuild, Workspace, WorkspaceContext, WorkspaceImageSource, WorkspaceImageSourceDocker, WorkspaceImageSourceReference, WorkspaceInstance, WorkspaceInstanceConfiguration, WorkspaceInstanceStatus, WorkspaceProbeContext, Permission, HeadlessLogEvent, HeadlessWorkspaceEventType, DisposableCollection, AdditionalContentContext, ImageConfigFile, EmailType } from "@gitpod/gitpod-protocol"; +import { CommitContext, Disposable, GitpodToken, GitpodTokenType, IssueContext, NamedWorkspaceFeatureFlag, PullRequestContext, RefType, SnapshotContext, StartWorkspaceResult, User, UserEnvVar, UserEnvVarValue, WithEnvvarsContext, WithPrebuild, Workspace, WorkspaceContext, WorkspaceImageSource, WorkspaceImageSourceDocker, WorkspaceImageSourceReference, WorkspaceInstance, WorkspaceInstanceConfiguration, WorkspaceInstanceStatus, WorkspaceProbeContext, Permission, HeadlessLogEvent, HeadlessWorkspaceEventType, DisposableCollection, AdditionalContentContext, ImageConfigFile } from "@gitpod/gitpod-protocol"; import { IAnalyticsWriter } from '@gitpod/gitpod-protocol/lib/analytics'; import { log } from '@gitpod/gitpod-protocol/lib/util/logging'; import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing"; @@ -728,7 +728,7 @@ export class WorkspaceStarter { const gitSpec = new GitSpec(); gitSpec.setUsername(user.fullName || identity.authName); - gitSpec.setEmail(identity.additionalEmails?.find(e => e.type === EmailType.COMMIT)?.address || identity.primaryEmail!); + gitSpec.setEmail(identity.primaryEmail!); return gitSpec; }