Skip to content
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

Email confirmation/update #1568

Merged
merged 69 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
5ad3a90
lexicons
dholms Sep 8, 2023
f97e3ab
codegen
dholms Sep 8, 2023
ea1e6cc
email templates
dholms Sep 8, 2023
c4cf9fa
request routes
dholms Sep 8, 2023
57aec22
impl
dholms Sep 8, 2023
5dfd97f
migration
dholms Sep 8, 2023
a80966f
tidy
dholms Sep 8, 2023
96d0f01
tests
dholms Sep 8, 2023
b718599
Merge branch 'main' into email-confirmation
dholms Sep 8, 2023
81a3f56
tidy & bugfixes
dholms Sep 8, 2023
e2f7a9a
format
dholms Sep 8, 2023
b796ad2
fix api test
dholms Sep 8, 2023
b223271
fix auth test
dholms Sep 8, 2023
4ec7c01
Merge branch 'main' into email-confirmation
dholms Sep 12, 2023
626ac31
codegen
dholms Sep 12, 2023
009db47
add unique constraint
dholms Sep 12, 2023
ce2e196
Add email confirmed to AtpSessionData
pfrazee Sep 26, 2023
4fc3b5f
interop test files (#1529)
bnewbold Sep 13, 2023
f7a5db3
add getSuggestedFollowsByActor (#1553)
estrattonbailey Sep 13, 2023
ddb79cb
List feeds (#1557)
dholms Sep 14, 2023
6ac232c
Improve xrpc server error handling (#1597)
dholms Sep 14, 2023
95e64cb
Remove appview proxy runtime flags (#1590)
dholms Sep 14, 2023
fc63115
getPopular hotfix (#1599)
dholms Sep 14, 2023
2b8157f
Interaction Gating (#1561)
dholms Sep 14, 2023
9db8c35
order by `like.indexedAt` in app view (#1592)
estrattonbailey Sep 14, 2023
d7dd136
Remove default value for post table invalid attrs (#1601)
dholms Sep 14, 2023
d976bba
Version packages (#1602)
github-actions[bot] Sep 14, 2023
b15974c
update Bluesky PBLLC to PBC (Public Benefit Corporation) (#1600)
bnewbold Sep 14, 2023
4db5770
Temporarily disable filtering `invalidReplyRoot`s (#1609)
dholms Sep 15, 2023
d7eff88
fix syntax docs (#1611)
estrattonbailey Sep 15, 2023
2919e44
Version packages (#1612)
github-actions[bot] Sep 15, 2023
54a1184
Allow bypass on ratelimit ip (#1613)
dholms Sep 15, 2023
0874edb
Write rate limits (#1578)
dholms Sep 15, 2023
0b7439c
Tweak createSession rate limit key (#1614)
dholms Sep 15, 2023
3de42df
Filter preferences for app passwords (#1626)
dholms Sep 18, 2023
1ca0ca8
Tweak rate limit setup for multi rate limit routes (#1627)
dholms Sep 18, 2023
50d6760
Remove zod from xrpc-server error handling (#1631)
dholms Sep 19, 2023
bb3f94c
Enforce properties field on lexicon object schemas (#1628)
dholms Sep 19, 2023
c9c8d40
Add feed-vew and thread-view preferences (#1638)
pfrazee Sep 20, 2023
0982846
Add changeset for new preferences (#1639)
pfrazee Sep 20, 2023
3bd26b1
Version packages (#1640)
github-actions[bot] Sep 20, 2023
58dc1f5
Disable getAccountInviteCodes for app passwords (#1642)
dholms Sep 21, 2023
803beae
remove cruft packages (uri, nsid, identifier) (#1606)
bnewbold Sep 21, 2023
12b7a60
api: update login/resumeSession examples in README (#1634)
bnewbold Sep 21, 2023
40f29f9
small syntax lints (#1646)
bnewbold Sep 21, 2023
51b03dc
indicate that getPopular is deprecated (#1647)
bnewbold Sep 21, 2023
6027d36
tidy up package.json and READMEs (#1649)
bnewbold Sep 22, 2023
91e24ff
Improve the types of the thread and feed preferences APIs (#1653)
pfrazee Sep 22, 2023
93fea5f
Version packages (#1654)
github-actions[bot] Sep 22, 2023
607d94f
Disable pds appview routes (#1644)
dholms Sep 22, 2023
8a62d6e
auto-moderator tweaks: pass along record URI, create report for taked…
bnewbold Sep 23, 2023
e67c2d7
Clear follow viewer state when blocking (#1659)
devinivy Sep 25, 2023
4e98627
add `tags` to posts (#1637)
estrattonbailey Sep 25, 2023
0e8fb99
Version packages (#1664)
github-actions[bot] Sep 25, 2023
6348cfa
merge
dholms Sep 26, 2023
b2be947
Reverse order of blocks from sync.getRepo (#1665)
dholms Sep 25, 2023
2b0790a
Add hashtag detection to richtext (#1651)
estrattonbailey Sep 25, 2023
df63b05
Version packages (#1669)
github-actions[bot] Sep 25, 2023
f8a9946
proposed new search lexicons (#1594)
bnewbold Sep 25, 2023
1db3d72
Disable pds appview indexing (#1645)
dholms Sep 26, 2023
692f541
Refactor PDS appview routes (#1673)
dholms Sep 26, 2023
76a014d
Strip leading `#` from from detected tag facets (#1674)
estrattonbailey Sep 26, 2023
ac913fb
Version packages (#1675)
github-actions[bot] Sep 26, 2023
09ec731
Proxy search queries (#1676)
dholms Sep 26, 2023
a0d467a
add mock mailer
dholms Sep 26, 2023
3ee4573
merge
dholms Sep 26, 2023
1e62fef
Fix to daniel's MOCKERY of a mock mailer
pfrazee Sep 27, 2023
91c05fe
Don't allow non-verified email updates until app feature is out (#1682)
dholms Sep 27, 2023
0508ae7
changesets
dholms Sep 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/little-fans-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@atproto/dev-env': patch
'@atproto/api': patch
'@atproto/pds': patch
---

Added email verification and update flows
5 changes: 5 additions & 0 deletions .changeset/witty-islands-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@atproto/common-web': patch
---

Added lessThanAgoMs utility
27 changes: 27 additions & 0 deletions lexicons/com/atproto/server/confirmEmail.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"lexicon": 1,
"id": "com.atproto.server.confirmEmail",
"defs": {
"main": {
"type": "procedure",
"description": "Confirm an email using a token from com.atproto.server.requestEmailConfirmation.",
"input": {
"encoding": "application/json",
"schema": {
"type": "object",
"required": ["email", "token"],
"properties": {
"email": { "type": "string" },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two questions here:

  • Does this need to be the email address, or is there a possibility of matching the createSession endpoint by making it an opaque identifier?
  • If the user is verifying while logged-in, could this input be optional?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking here is that it's an extra integrity check on email.

Imagine the following flow:

This is very unlikely. I'm not sure we need to defend against it and we may have a better mechanism by which to do it (storing that state in the db?)

"token": { "type": "string" }
}
}
},
"errors": [
{ "name": "AccountNotFound" },
{ "name": "ExpiredToken" },
{ "name": "InvalidToken" },
{ "name": "InvalidEmail" }
]
}
}
}
3 changes: 2 additions & 1 deletion lexicons/com/atproto/server/createSession.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"refreshJwt": { "type": "string" },
"handle": { "type": "string", "format": "handle" },
"did": { "type": "string", "format": "did" },
"email": { "type": "string" }
"email": { "type": "string" },
"emailConfirmed": { "type": "boolean" }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a gut thing, but these email-specific methods and params feel a little bit narrow to me. At the same time, I do think we should probably just roll with it. Maybe for fun worth scanning over this old approach, which includes confirmation/verification: https://github.com/bluesky-social/atproto/compare/2fa

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. I see what you're saying 🤔

This would be fairly easy to switch over and may save us from some future deprecation

}
}
},
Expand Down
3 changes: 2 additions & 1 deletion lexicons/com/atproto/server/getSession.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"properties": {
"handle": { "type": "string", "format": "handle" },
"did": { "type": "string", "format": "did" },
"email": { "type": "string" }
"email": { "type": "string" },
"emailConfirmed": { "type": "boolean" }
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions lexicons/com/atproto/server/requestEmailConfirmation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"lexicon": 1,
"id": "com.atproto.server.requestEmailConfirmation",
"defs": {
"main": {
"type": "procedure",
"description": "Request an email with a code to confirm ownership of email"
}
}
}
20 changes: 20 additions & 0 deletions lexicons/com/atproto/server/requestEmailUpdate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"lexicon": 1,
"id": "com.atproto.server.requestEmailUpdate",
"defs": {
"main": {
"type": "procedure",
"description": "Request a token in order to update email.",
"output": {
"encoding": "application/json",
"schema": {
"type": "object",
"required": ["tokenRequired"],
"properties": {
"tokenRequired": { "type": "boolean" }
}
}
}
}
}
}
29 changes: 29 additions & 0 deletions lexicons/com/atproto/server/updateEmail.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"lexicon": 1,
"id": "com.atproto.server.updateEmail",
"defs": {
"main": {
"type": "procedure",
"description": "Update an account's email.",
"input": {
"encoding": "application/json",
"schema": {
"type": "object",
"required": ["email"],
"properties": {
"email": { "type": "string" },
"token": {
"type": "string",
"description": "Requires a token from com.atproto.sever.requestEmailUpdate if the account's email has been confirmed."
}
}
}
},
"errors": [
{ "name": "ExpiredToken" },
{ "name": "InvalidToken" },
{ "name": "TokenRequired" }
]
}
}
}
4 changes: 4 additions & 0 deletions packages/api/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export class AtpAgent {
handle: res.data.handle,
did: res.data.did,
email: opts.email,
emailConfirmed: false,
}
return res
} catch (e) {
Expand Down Expand Up @@ -126,6 +127,7 @@ export class AtpAgent {
handle: res.data.handle,
did: res.data.did,
email: res.data.email,
emailConfirmed: res.data.emailConfirmed,
}
return res
} catch (e) {
Expand Down Expand Up @@ -154,6 +156,7 @@ export class AtpAgent {
}
this.session.email = res.data.email
this.session.handle = res.data.handle
this.session.emailConfirmed = res.data.emailConfirmed
return res
} catch (e) {
this.session = undefined
Expand Down Expand Up @@ -268,6 +271,7 @@ export class AtpAgent {
} else if (isNewSessionObject(this._baseClient, res.body)) {
// succeeded, update the session
this.session = {
...(this.session || {}),
accessJwt: res.body.accessJwt,
refreshJwt: res.body.refreshJwt,
handle: res.body.handle,
Expand Down
52 changes: 52 additions & 0 deletions packages/api/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords
import * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord'
import * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef'
import * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob'
import * as ComAtprotoServerConfirmEmail from './types/com/atproto/server/confirmEmail'
import * as ComAtprotoServerCreateAccount from './types/com/atproto/server/createAccount'
import * as ComAtprotoServerCreateAppPassword from './types/com/atproto/server/createAppPassword'
import * as ComAtprotoServerCreateInviteCode from './types/com/atproto/server/createInviteCode'
Expand All @@ -55,9 +56,12 @@ import * as ComAtprotoServerGetSession from './types/com/atproto/server/getSessi
import * as ComAtprotoServerListAppPasswords from './types/com/atproto/server/listAppPasswords'
import * as ComAtprotoServerRefreshSession from './types/com/atproto/server/refreshSession'
import * as ComAtprotoServerRequestAccountDelete from './types/com/atproto/server/requestAccountDelete'
import * as ComAtprotoServerRequestEmailConfirmation from './types/com/atproto/server/requestEmailConfirmation'
import * as ComAtprotoServerRequestEmailUpdate from './types/com/atproto/server/requestEmailUpdate'
import * as ComAtprotoServerRequestPasswordReset from './types/com/atproto/server/requestPasswordReset'
import * as ComAtprotoServerResetPassword from './types/com/atproto/server/resetPassword'
import * as ComAtprotoServerRevokeAppPassword from './types/com/atproto/server/revokeAppPassword'
import * as ComAtprotoServerUpdateEmail from './types/com/atproto/server/updateEmail'
import * as ComAtprotoSyncGetBlob from './types/com/atproto/sync/getBlob'
import * as ComAtprotoSyncGetBlocks from './types/com/atproto/sync/getBlocks'
import * as ComAtprotoSyncGetCheckout from './types/com/atproto/sync/getCheckout'
Expand Down Expand Up @@ -170,6 +174,7 @@ export * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords
export * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord'
export * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef'
export * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob'
export * as ComAtprotoServerConfirmEmail from './types/com/atproto/server/confirmEmail'
export * as ComAtprotoServerCreateAccount from './types/com/atproto/server/createAccount'
export * as ComAtprotoServerCreateAppPassword from './types/com/atproto/server/createAppPassword'
export * as ComAtprotoServerCreateInviteCode from './types/com/atproto/server/createInviteCode'
Expand All @@ -184,9 +189,12 @@ export * as ComAtprotoServerGetSession from './types/com/atproto/server/getSessi
export * as ComAtprotoServerListAppPasswords from './types/com/atproto/server/listAppPasswords'
export * as ComAtprotoServerRefreshSession from './types/com/atproto/server/refreshSession'
export * as ComAtprotoServerRequestAccountDelete from './types/com/atproto/server/requestAccountDelete'
export * as ComAtprotoServerRequestEmailConfirmation from './types/com/atproto/server/requestEmailConfirmation'
export * as ComAtprotoServerRequestEmailUpdate from './types/com/atproto/server/requestEmailUpdate'
export * as ComAtprotoServerRequestPasswordReset from './types/com/atproto/server/requestPasswordReset'
export * as ComAtprotoServerResetPassword from './types/com/atproto/server/resetPassword'
export * as ComAtprotoServerRevokeAppPassword from './types/com/atproto/server/revokeAppPassword'
export * as ComAtprotoServerUpdateEmail from './types/com/atproto/server/updateEmail'
export * as ComAtprotoSyncGetBlob from './types/com/atproto/sync/getBlob'
export * as ComAtprotoSyncGetBlocks from './types/com/atproto/sync/getBlocks'
export * as ComAtprotoSyncGetCheckout from './types/com/atproto/sync/getCheckout'
Expand Down Expand Up @@ -712,6 +720,17 @@ export class ServerNS {
this._service = service
}

confirmEmail(
data?: ComAtprotoServerConfirmEmail.InputSchema,
opts?: ComAtprotoServerConfirmEmail.CallOptions,
): Promise<ComAtprotoServerConfirmEmail.Response> {
return this._service.xrpc
.call('com.atproto.server.confirmEmail', opts?.qp, data, opts)
.catch((e) => {
throw ComAtprotoServerConfirmEmail.toKnownErr(e)
})
}

createAccount(
data?: ComAtprotoServerCreateAccount.InputSchema,
opts?: ComAtprotoServerCreateAccount.CallOptions,
Expand Down Expand Up @@ -855,6 +874,28 @@ export class ServerNS {
})
}

requestEmailConfirmation(
data?: ComAtprotoServerRequestEmailConfirmation.InputSchema,
opts?: ComAtprotoServerRequestEmailConfirmation.CallOptions,
): Promise<ComAtprotoServerRequestEmailConfirmation.Response> {
return this._service.xrpc
.call('com.atproto.server.requestEmailConfirmation', opts?.qp, data, opts)
.catch((e) => {
throw ComAtprotoServerRequestEmailConfirmation.toKnownErr(e)
})
}

requestEmailUpdate(
data?: ComAtprotoServerRequestEmailUpdate.InputSchema,
opts?: ComAtprotoServerRequestEmailUpdate.CallOptions,
): Promise<ComAtprotoServerRequestEmailUpdate.Response> {
return this._service.xrpc
.call('com.atproto.server.requestEmailUpdate', opts?.qp, data, opts)
.catch((e) => {
throw ComAtprotoServerRequestEmailUpdate.toKnownErr(e)
})
}

requestPasswordReset(
data?: ComAtprotoServerRequestPasswordReset.InputSchema,
opts?: ComAtprotoServerRequestPasswordReset.CallOptions,
Expand Down Expand Up @@ -887,6 +928,17 @@ export class ServerNS {
throw ComAtprotoServerRevokeAppPassword.toKnownErr(e)
})
}

updateEmail(
data?: ComAtprotoServerUpdateEmail.InputSchema,
opts?: ComAtprotoServerUpdateEmail.CallOptions,
): Promise<ComAtprotoServerUpdateEmail.Response> {
return this._service.xrpc
.call('com.atproto.server.updateEmail', opts?.qp, data, opts)
.catch((e) => {
throw ComAtprotoServerUpdateEmail.toKnownErr(e)
})
}
}

export class SyncNS {
Expand Down
Loading
Loading