-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f55f109
commit f157d5d
Showing
26 changed files
with
359 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/** | ||
* Copyright (c) 2022 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 { useState } from "react"; | ||
import Alert from "../components/Alert"; | ||
import Modal from "../components/Modal"; | ||
|
||
interface VerifyModalState { | ||
phoneNumber?: string; | ||
sent?: Date; | ||
token?: string; | ||
} | ||
|
||
export function VerifyModal() { | ||
const [state, setState] = useState<VerifyModalState>({}); | ||
const sendCode = () => {}; | ||
const isValidPhoneNumber = () => { | ||
return !!state.phoneNumber && /\+[0-9]{5,}/.test(state.phoneNumber); | ||
}; | ||
return ( | ||
<Modal | ||
onClose={() => {}} | ||
onEnter={() => false} | ||
title="User Validation Required" | ||
buttons={ | ||
<div> | ||
<button className="ml-2" disabled={!isValidPhoneNumber()} onClick={sendCode}> | ||
Send Code via SMS | ||
</button> | ||
</div> | ||
} | ||
visible={true} | ||
> | ||
<Alert type="warning" className="mt-2"> | ||
To try Gitpod for free you'll need to validate your account with your phone number. This is required to | ||
discourage and reduce abuse on Gitpod infrastructure. | ||
</Alert> | ||
<div className="border-t border-gray-200 dark:border-gray-800 mt-2 -mx-6 px-6 pt-4"> | ||
Enter your mobile phone number to verify your account. | ||
</div> | ||
<div className="mt-4"> | ||
<h4>Mobile Phone Number</h4> | ||
<input | ||
type="text" | ||
placeholder="+123242345345" | ||
value={state.phoneNumber} | ||
onChange={(v) => { | ||
setState({ | ||
...state, | ||
phoneNumber: v.currentTarget.value, | ||
}); | ||
}} | ||
/> | ||
</div> | ||
<div className="mt-4"> | ||
<h4>Verification Code</h4> | ||
<input | ||
className="w-full" | ||
type="text" | ||
placeholder="enter token send via sms" | ||
value={state.token} | ||
onChange={(v) => { | ||
setState({ | ||
...state, | ||
token: v.currentTarget.value, | ||
}); | ||
}} | ||
/> | ||
</div> | ||
</Modal> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/** | ||
* Copyright (c) 2022 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 { User } from "@gitpod/gitpod-protocol"; | ||
import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; | ||
import { inject, injectable, postConstruct } from "inversify"; | ||
import { Config } from "../config"; | ||
import { Twilio } from "twilio"; | ||
import { ServiceContext } from "twilio/lib/rest/verify/v2/service"; | ||
import { UserDB, WorkspaceDB } from "@gitpod/gitpod-db/lib"; | ||
|
||
@injectable() | ||
export class VerificationService { | ||
@inject(Config) protected config: Config; | ||
@inject(WorkspaceDB) protected workspaceDB: WorkspaceDB; | ||
@inject(UserDB) protected userDB: UserDB; | ||
|
||
protected verifyService: ServiceContext; | ||
|
||
@postConstruct() | ||
protected initialize(): void { | ||
if (this.config.twilioConfig) { | ||
const client = new Twilio(this.config.twilioConfig.accountSID, this.config.twilioConfig.authToken); | ||
this.verifyService = client.verify.v2.services(this.config.twilioConfig.serviceName); | ||
} | ||
} | ||
|
||
public async needsVerification(user: User): Promise<boolean> { | ||
if (!this.config.twilioConfig) { | ||
return false; | ||
} | ||
if (!!user.additionalData?.lastVerificationTime) { | ||
return false; | ||
} | ||
if (await this.isTrusted(user)) { | ||
await this.markVerified(user); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
public async markVerified(user: User): Promise<User> { | ||
if (!user.additionalData) { | ||
user.additionalData = {}; | ||
} | ||
user.additionalData!.lastVerificationTime = new Date().toISOString(); | ||
await this.userDB.updateUserPartial(user); | ||
return user; | ||
} | ||
|
||
private async isTrusted(user: User): Promise<boolean> { | ||
// we only want to ask new users, so if a user has ever started workspaces before, we trust them. | ||
// there might be a few false positives because all workspaces might have been deleted. | ||
const workspaces = await this.workspaceDB.findWorkspacesByUser(user.id); | ||
return workspaces.length !== 0; | ||
} | ||
|
||
public async sendVerificationToken(phoneNumber: string): Promise<void> { | ||
if (!this.verifyService) { | ||
throw new Error("No verification service configured."); | ||
} | ||
const verification = await this.verifyService.verifications.create({ to: phoneNumber, channel: "sms" }); | ||
log.info("Verification code sent", { phoneNumber, status: verification.status }); | ||
} | ||
|
||
public async verifyVerificationToken(phoneNumber: string, oneTimePassword: string): Promise<boolean> { | ||
if (!this.verifyService) { | ||
throw new Error("No verification service configured."); | ||
} | ||
const verification_check = await this.verifyService.verificationChecks.create({ | ||
to: phoneNumber, | ||
code: oneTimePassword, | ||
}); | ||
return verification_check.status === "approved"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.