- 
        Couldn't load subscription status. 
- Fork 26
feat: register, change and verify email addresses #148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
046298c
              9bfbf4d
              89429d1
              f421aa0
              000faa2
              b465f2f
              be5fb7d
              5b8e3cf
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| import { deleteEndpoint, getEndpoint, postEndpoint } from './endpoint' | ||
| import { deleteEndpoint, getEndpoint, postEndpoint, putEndpoint } from './endpoint' | ||
| import type { operations } from './types/api' | ||
| import type { | ||
| SafeTransactionEstimation, | ||
|  | @@ -25,6 +25,7 @@ import type { DecodedDataResponse } from './types/decoded-data' | |
| import type { SafeMessage, SafeMessageListPage } from './types/safe-messages' | ||
| import { DEFAULT_BASE_URL } from './config' | ||
| import type { DelegateResponse, DelegatesRequest } from './types/delegates' | ||
| import type { GetEmailResponse } from './types/emails' | ||
|  | ||
| export * from './types/safe-info' | ||
| export * from './types/safe-apps' | ||
|  | @@ -413,4 +414,130 @@ export function unregisterDevice(chainId: string, uuid: string): Promise<void> { | |
| }) | ||
| } | ||
|  | ||
| /** | ||
| * Registers a email address for a safe signer. | ||
| * | ||
| * The signer wallet has to sign a message of format: `email-register-{chainId}-{safeAddress}-{emailAddress}-{signer}-{timestamp}` | ||
| * The signature is valid for 5 minutes. | ||
| * | ||
| * @param chainId | ||
| * @param safeAddress | ||
| * @param body Signer address and email address | ||
| * @param headers Signature and Signature timestamp | ||
| * @returns 200 if signature matches the data | ||
| */ | ||
| export function registerEmail( | ||
| chainId: string, | ||
| safeAddress: string, | ||
| body: operations['register_email']['parameters']['body'], | ||
| headers: operations['register_email']['parameters']['headers'], | ||
| ): Promise<void> { | ||
| return postEndpoint(baseUrl, '/v1/chains/{chainId}/safes/{safe_address}/emails', { | ||
| path: { chainId, safe_address: safeAddress }, | ||
| body, | ||
| headers, | ||
| }) | ||
| } | ||
|  | ||
| /** | ||
| * Changes an already registered email address for a safe signer. The new email address still needs to be verified. | ||
| * | ||
| * The signer wallet has to sign a message of format: `email-edit-{chainId}-{safeAddress}-{emailAddress}-{signer}-{timestamp}` | ||
| * The signature is valid for 5 minutes. | ||
| * | ||
| * @param chainId | ||
| * @param safeAddress | ||
| * @param body New email address | ||
| * @param headers Signature and Signature timestamp | ||
| * @returns 202 if signature matches the data | ||
| */ | ||
| export function changeEmail( | ||
| chainId: string, | ||
| safeAddress: string, | ||
| signerAddress: string, | ||
| body: operations['change_email']['parameters']['body'], | ||
| headers: operations['change_email']['parameters']['headers'], | ||
| ): Promise<void> { | ||
| return putEndpoint(baseUrl, '/v1/chains/{chainId}/safes/{safe_address}/emails/{signer}', { | ||
| path: { chainId, safe_address: safeAddress, signer: signerAddress }, | ||
| body, | ||
| headers, | ||
| }) | ||
| } | ||
|  | ||
| /** | ||
| * Resends an email verification code. | ||
| */ | ||
| export function resendEmailVerificationCode( | ||
| chainId: string, | ||
| safeAddress: string, | ||
| signerAddress: string, | ||
| ): Promise<void> { | ||
| return postEndpoint(baseUrl, '/v1/chains/{chainId}/safes/{safe_address}/emails/{signer}/verify-resend', { | ||
| path: { chainId, safe_address: safeAddress, signer: signerAddress }, | ||
| body: '', | ||
| }) | ||
| } | ||
|  | ||
| /** | ||
| * Verifies a pending email address registration. | ||
| * | ||
| * @param chainId | ||
| * @param safeAddress | ||
| * @param signerAddress address who signed the email registration | ||
| * @param body Verification code | ||
| */ | ||
| export function verifyEmail( | ||
| chainId: string, | ||
| safeAddress: string, | ||
| signerAddress: string, | ||
| body: operations['verify_email']['parameters']['body'], | ||
| ): Promise<void> { | ||
| return putEndpoint(baseUrl, '/v1/chains/{chainId}/safes/{safe_address}/emails/{signer}/verify', { | ||
| path: { chainId, safe_address: safeAddress, signer: signerAddress }, | ||
| body, | ||
| }) | ||
| } | ||
|  | ||
| /** | ||
| * Gets the registered email address of the signer | ||
| * | ||
| * @param chainId | ||
| * @param safeAddress | ||
| * @param signerAddress address of the owner of the Safe | ||
| * | ||
| * @returns email address and verified flag | ||
| */ | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since it's mentioned in the other authenticated endpoints. This one also requires a signature:  | ||
| export function getRegisteredEmail( | ||
| chainId: string, | ||
| safeAddress: string, | ||
| signerAddress: string, | ||
| headers: operations['get_email']['parameters']['headers'], | ||
| ): Promise<GetEmailResponse> { | ||
| return getEndpoint(baseUrl, '/v1/chains/{chainId}/safes/{safe_address}/emails/{signer}', { | ||
| path: { chainId, safe_address: safeAddress, signer: signerAddress }, | ||
| headers, | ||
| }) | ||
| } | ||
|  | ||
| /** | ||
| * Delete a registered email address for the signer | ||
| * | ||
| * @param chainId | ||
| * @param safeAddress | ||
| * @param signerAddress | ||
| * @param headers | ||
| */ | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as my comment above. Signature would be  | ||
| export function deleteRegisteredEmail( | ||
| chainId: string, | ||
| safeAddress: string, | ||
| signerAddress: string, | ||
| headers: operations['delete_email']['parameters']['headers'], | ||
| ): Promise<void> { | ||
| return deleteEndpoint(baseUrl, '/v1/chains/{chainId}/safes/{safe_address}/emails/{signer}', { | ||
| path: { chainId, safe_address: safeAddress, signer: signerAddress }, | ||
| headers, | ||
| }) | ||
| } | ||
|  | ||
| /* eslint-enable @typescript-eslint/explicit-module-boundary-types */ | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -30,11 +30,19 @@ import type { | |
| } from './safe-messages' | ||
| import type { DelegateResponse, DelegatesRequest } from './delegates' | ||
| import type { RegisterNotificationsRequest } from './notifications' | ||
| import type { | ||
| ChangeEmailRequestBody, | ||
| GetEmailResponse, | ||
| RegisterEmailRequestBody, | ||
| AuthorizationEmailRequestHeader, | ||
| VerifyEmailRequestBody, | ||
| } from './emails' | ||
|  | ||
| export type Primitive = string | number | boolean | null | ||
|  | ||
| interface Params { | ||
| path?: { [key: string]: Primitive } | ||
| headers?: Record<string, string> | ||
| } | ||
|  | ||
| interface GetParams extends Params { | ||
|  | @@ -70,6 +78,13 @@ export interface PostEndpoint extends Endpoint { | |
| } | ||
| } | ||
|  | ||
| export interface PutEndpoint extends Endpoint { | ||
| put: { | ||
| parameters: PostParams | null | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not duplicate the types here as they are identical. 
 | ||
| responses: Responses | ||
| } | ||
| } | ||
|  | ||
| export interface DeleteEndpoint extends Endpoint { | ||
| delete: { | ||
| parameters: Params | null | ||
|  | @@ -78,7 +93,7 @@ export interface DeleteEndpoint extends Endpoint { | |
| } | ||
|  | ||
| interface PathRegistry { | ||
| [key: string]: GetEndpoint | PostEndpoint | (GetEndpoint & PostEndpoint) | DeleteEndpoint | ||
| [key: string]: GetEndpoint | PostEndpoint | PutEndpoint | DeleteEndpoint | ||
| } | ||
|  | ||
| export interface paths extends PathRegistry { | ||
|  | @@ -332,6 +347,47 @@ export interface paths extends PathRegistry { | |
| } | ||
| } | ||
| } | ||
| '/v1/chains/{chainId}/safes/{safe_address}/emails': { | ||
| post: operations['register_email'] | ||
| parameters: { | ||
| path: { | ||
| chainId: string | ||
| safe_address: string | ||
| } | ||
| } | ||
| } | ||
| '/v1/chains/{chainId}/safes/{safe_address}/emails/{signer}': { | ||
| put: operations['change_email'] | ||
| get: operations['get_email'] | ||
| delete: operations['delete_email'] | ||
| parameters: { | ||
| path: { | ||
| chainId: string | ||
| safe_address: string | ||
| signer: string | ||
| } | ||
| } | ||
| } | ||
| '/v1/chains/{chainId}/safes/{safe_address}/emails/{signer}/verify-resend': { | ||
| post: operations['verify_resend'] | ||
| parameters: { | ||
| path: { | ||
| chainId: string | ||
| safe_address: string | ||
| signer: string | ||
| } | ||
| } | ||
| } | ||
| '/v1/chains/{chainId}/safes/{safe_address}/emails/{signer}/verify': { | ||
| put: operations['verify_email'] | ||
| parameters: { | ||
| path: { | ||
| chainId: string | ||
| safe_address: string | ||
| signer: string | ||
| } | ||
| } | ||
| } | ||
| } | ||
|  | ||
| export interface operations { | ||
|  | @@ -833,4 +889,113 @@ export interface operations { | |
| } | ||
| } | ||
| } | ||
| register_email: { | ||
| parameters: { | ||
| path: { | ||
| chainId: string | ||
| safe_address: string | ||
| } | ||
| body: RegisterEmailRequestBody | ||
| headers: AuthorizationEmailRequestHeader | ||
| } | ||
| responses: { | ||
| 200: { | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here it should be 201. | ||
| schema: void | ||
| } | ||
| } | ||
| } | ||
| change_email: { | ||
| parameters: { | ||
| path: { | ||
| chainId: string | ||
| safe_address: string | ||
| signer: string | ||
| } | ||
| body: ChangeEmailRequestBody | ||
| headers: AuthorizationEmailRequestHeader | ||
| } | ||
| responses: { | ||
| 200: { | ||
| schema: void | ||
| } | ||
| 202: { | ||
| schema: void | ||
| } | ||
| } | ||
| 
      Comment on lines
    
      +920
     to 
      +927
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this only include successful responses? If so then only  | ||
| } | ||
| get_email: { | ||
| parameters: { | ||
| path: { | ||
| chainId: string | ||
| safe_address: string | ||
| signer: string | ||
| } | ||
| headers: AuthorizationEmailRequestHeader | ||
| } | ||
| responses: { | ||
| 200: { | ||
| schema: GetEmailResponse | ||
| } | ||
| } | ||
| } | ||
| verify_resend: { | ||
| parameters: { | ||
| path: { | ||
| chainId: string | ||
| safe_address: string | ||
| signer: string | ||
| } | ||
| body: '' | ||
| } | ||
| responses: { | ||
| 202: { | ||
| schema: void | ||
| } | ||
| 200: { | ||
| schema: void | ||
| } | ||
| 429: unknown | ||
| 409: unknown | ||
| } | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI: After safe-global/safe-client-gateway#1181 is merged, only 202 will be returned. | ||
| } | ||
| verify_email: { | ||
| parameters: { | ||
| path: { | ||
| chainId: string | ||
| safe_address: string | ||
| signer: string | ||
| } | ||
| body: VerifyEmailRequestBody | ||
| } | ||
|  | ||
| responses: { | ||
| 204: { | ||
| schema: void | ||
| } | ||
| 200: { | ||
| schema: void | ||
| } | ||
| 
      Comment on lines
    
      +976
     to 
      +978
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This status code is not expected to be returned on this endpoint. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently our types enforce a 200 response code this. We should look into how to make them more flexible. | ||
| 400: unknown | ||
| } | ||
| } | ||
| delete_email: { | ||
| parameters: { | ||
| path: { | ||
| chainId: string | ||
| safe_address: string | ||
| signer: string | ||
| } | ||
| headers: AuthorizationEmailRequestHeader | ||
| } | ||
|  | ||
| responses: { | ||
| 204: { | ||
| schema: void | ||
| } | ||
| 200: { | ||
| schema: void | ||
| } | ||
| 403: unknown | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.