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

Account deletion #488

Merged
merged 94 commits into from
Feb 2, 2023
Merged
Show file tree
Hide file tree
Changes from 92 commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
7a0aa9a
wip
dholms Dec 21, 2022
6129e36
fleshing out repo storage
dholms Dec 21, 2022
f6e8b9f
fleshing out sql storage
dholms Dec 21, 2022
4f369f5
cleaning things up
dholms Dec 21, 2022
fb679e4
fix up tests
dholms Dec 21, 2022
ab06c1e
Merge branch 'main' into repo-storage-sync
dholms Dec 21, 2022
a6cf302
dumb bug - commit log reversed
dholms Dec 21, 2022
de0ed28
rm staging in favor of commiting diffs to blockstore
dholms Dec 22, 2022
1397b52
clean up benches
dholms Dec 22, 2022
98f43e2
fixing up sql storage
dholms Dec 22, 2022
32262cc
some caching for sql repo store
dholms Dec 22, 2022
814f5fe
pr feedback
dholms Dec 23, 2022
a5e2e8e
merge
dholms Dec 23, 2022
1497d05
migration
dholms Dec 23, 2022
432d53c
wip
dholms Dec 23, 2022
68bff2a
migraiton test
dholms Dec 26, 2022
6a983e4
unclear param
dholms Dec 26, 2022
abc3fec
Merge branch 'repo-storage-sync' into repo-mutation-diffs
dholms Dec 26, 2022
d66751f
Merge branch 'repo-mutation-diffs' into repo-storage-migration
dholms Dec 26, 2022
f03605c
sql repo storage tests
dholms Dec 26, 2022
5ccbfaf
rm unused code
dholms Dec 26, 2022
3ad85db
fix up some diff code
dholms Dec 26, 2022
a21fb66
pr feedback
dholms Dec 26, 2022
11241b2
Merge branch 'repo-mutation-diffs' into repo-storage-migration
dholms Dec 26, 2022
f1e5ed8
enum for action types
dholms Dec 26, 2022
7a287f1
missed some
dholms Dec 26, 2022
380ef96
Merge branch 'repo-mutation-diffs' into repo-storage-migration
dholms Dec 26, 2022
32a21ab
wip
dholms Dec 27, 2022
d643250
ripping out auth lib
dholms Dec 27, 2022
69be03f
more auth cleanup
dholms Dec 28, 2022
b55f9d4
another lurker
dholms Dec 28, 2022
4523cad
wip better sync primitives
dholms Dec 29, 2022
6b11ba4
wip
dholms Dec 29, 2022
a5c913f
Merge branch 'repo-storage-sync' into sync-revamp
dholms Dec 29, 2022
dfc887c
Merge pull request #441 from bluesky-social/repo-mutation-diffs
dholms Dec 29, 2022
f9fd8a2
Merge pull request #443 from bluesky-social/repo-storage-migration
dholms Dec 29, 2022
8e7131d
improving diffs & sync
dholms Dec 29, 2022
d6cd794
tests working!
dholms Dec 29, 2022
fe109c6
actually implemented checkout lol
dholms Dec 30, 2022
a1ed8c3
Merge branch 'sync-revamp' into repo-checkout
dholms Dec 30, 2022
fdd60f7
simplify interface & improve error handling
dholms Dec 30, 2022
87abad4
writing sql storage code
dholms Dec 30, 2022
473bc92
fixing up tests
dholms Dec 30, 2022
0781d90
testing & bugfixes
dholms Jan 3, 2023
9f25a26
checkouts return records instead of cids
dholms Jan 3, 2023
8c1e9d5
one last refactor lol
dholms Jan 3, 2023
11970ef
missed one
dholms Jan 3, 2023
cff5b63
handle other cid codecs on incoming car verification
dholms Jan 3, 2023
b9b83d0
tests + tricky bugs
dholms Jan 3, 2023
c37082a
unneeded blockstore method
dholms Jan 3, 2023
6e58a0f
trim mst on del instead of save
dholms Jan 4, 2023
3269ad6
cleanup comment
dholms Jan 4, 2023
b8cfb78
dont resolve did for every commit
dholms Jan 4, 2023
156b332
use "commit" instead of "root"
dholms Jan 4, 2023
4953189
getRoot -> getHead
dholms Jan 4, 2023
716fb8b
pr feedback
dholms Jan 4, 2023
f647640
very silly bug fix
dholms Jan 4, 2023
00590c7
improve sync output
dholms Jan 4, 2023
423b6ab
Merge pull request #444 from bluesky-social/repo-checkout
dholms Jan 5, 2023
c3dc0b3
Merge pull request #460 from bluesky-social/record-write-descripts
dholms Jan 5, 2023
277e4a8
reorging + sync of particular records
dholms Jan 5, 2023
72cef57
serve & verify proofs. also rename some ipld methods
dholms Jan 6, 2023
7d271b5
fix up sync issue in mst
dholms Jan 6, 2023
bac84ce
find reachable records form carfile
dholms Jan 6, 2023
62355f4
getRecord xrpc method
dholms Jan 6, 2023
265b278
pr feedback
dholms Jan 18, 2023
08db20e
merged main
dholms Jan 18, 2023
98ba390
merge feature branch
dholms Jan 18, 2023
3f04e32
Merge pull request #462 from bluesky-social/narrow-clones
dholms Jan 18, 2023
281bd7e
merged amin
dholms Jan 19, 2023
fed8d9e
better migration test
dholms Jan 19, 2023
7d8a82e
check migraiton result
dholms Jan 19, 2023
f55e443
fixing up a couple things for pg
dholms Jan 19, 2023
2837034
explicit migrateTo
dholms Jan 20, 2023
aab057f
async exceptions
dholms Jan 20, 2023
aba06d3
Merge pull request #473 from bluesky-social/migration-test
dholms Jan 24, 2023
a39c8bc
ipld car mimetype + remove updateRepo
dholms Jan 24, 2023
19c03d5
Merge pull request #485 from bluesky-social/sync-mime-types
dholms Jan 24, 2023
c98059b
Update module publish scripts (#478)
pfrazee Jan 24, 2023
94b499e
Sort "suggested follows" by number of posts (#477)
dholms Jan 24, 2023
deb9740
partiion commit-history & commit-blocks by user did
dholms Jan 25, 2023
c5adea4
some lexicons
dholms Jan 24, 2023
fb5f565
delete records & repos
dholms Jan 25, 2023
af6fef6
delete blobs
dholms Jan 25, 2023
d513c4b
hook it up in route
dholms Jan 25, 2023
f33ea0e
pettier ignore email templates
dholms Jan 25, 2023
8e93735
testing & bugfixes
dholms Jan 26, 2023
54c4373
testing blobs & bugfixes
dholms Jan 26, 2023
4d4a0c7
pr feedback
dholms Jan 26, 2023
d409acb
make deletion test more robust
dholms Jan 26, 2023
d76d577
merge main
dholms Jan 27, 2023
2125fa4
change out handle for did on account deletion
dholms Jan 27, 2023
96493bc
merged main
dholms Feb 2, 2023
a35eecb
small cleanup
dholms Feb 2, 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
15 changes: 14 additions & 1 deletion lexicons/com/atproto/account/delete.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@
"defs": {
"main": {
"type": "procedure",
"description": "Delete an account."
"description": "Delete a user account with a token and password.",
"input": {
"encoding": "application/json",
"schema": {
"type": "object",
"required": ["did", "password", "token"],
"properties": {
"did": { "type": "string" },
"password": { "type": "string" },
"token": { "type": "string" }
}
}
},
"errors": [{ "name": "ExpiredToken" }, { "name": "InvalidToken" }]
}
}
}
10 changes: 10 additions & 0 deletions lexicons/com/atproto/account/requestDelete.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"lexicon": 1,
"id": "com.atproto.account.requestDelete",
"defs": {
"main": {
"type": "procedure",
"description": "Initiate a user account deletion via email."
}
}
}
13 changes: 13 additions & 0 deletions packages/api/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as ComAtprotoAccountCreate from './types/com/atproto/account/create'
import * as ComAtprotoAccountCreateInviteCode from './types/com/atproto/account/createInviteCode'
import * as ComAtprotoAccountDelete from './types/com/atproto/account/delete'
import * as ComAtprotoAccountGet from './types/com/atproto/account/get'
import * as ComAtprotoAccountRequestDelete from './types/com/atproto/account/requestDelete'
import * as ComAtprotoAccountRequestPasswordReset from './types/com/atproto/account/requestPasswordReset'
import * as ComAtprotoAccountResetPassword from './types/com/atproto/account/resetPassword'
import * as ComAtprotoAdminGetModerationAction from './types/com/atproto/admin/getModerationAction'
Expand Down Expand Up @@ -91,6 +92,7 @@ export * as ComAtprotoAccountCreate from './types/com/atproto/account/create'
export * as ComAtprotoAccountCreateInviteCode from './types/com/atproto/account/createInviteCode'
export * as ComAtprotoAccountDelete from './types/com/atproto/account/delete'
export * as ComAtprotoAccountGet from './types/com/atproto/account/get'
export * as ComAtprotoAccountRequestDelete from './types/com/atproto/account/requestDelete'
export * as ComAtprotoAccountRequestPasswordReset from './types/com/atproto/account/requestPasswordReset'
export * as ComAtprotoAccountResetPassword from './types/com/atproto/account/resetPassword'
export * as ComAtprotoAdminGetModerationAction from './types/com/atproto/admin/getModerationAction'
Expand Down Expand Up @@ -305,6 +307,17 @@ export class AccountNS {
})
}

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

requestPasswordReset(
data?: ComAtprotoAccountRequestPasswordReset.InputSchema,
opts?: ComAtprotoAccountRequestPasswordReset.CallOptions,
Expand Down
39 changes: 38 additions & 1 deletion packages/api/src/client/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,33 @@ export const schemaDict = {
defs: {
main: {
type: 'procedure',
description: 'Delete an account.',
description: 'Delete a user account with a token and password.',
input: {
encoding: 'application/json',
schema: {
type: 'object',
required: ['did', 'password', 'token'],
properties: {
did: {
type: 'string',
},
password: {
type: 'string',
},
token: {
type: 'string',
},
},
},
},
errors: [
{
name: 'ExpiredToken',
},
{
name: 'InvalidToken',
},
],
},
},
},
Expand All @@ -127,6 +153,16 @@ export const schemaDict = {
},
},
},
ComAtprotoAccountRequestDelete: {
lexicon: 1,
id: 'com.atproto.account.requestDelete',
defs: {
main: {
type: 'procedure',
description: 'Initiate a user account deletion via email.',
},
},
},
ComAtprotoAccountRequestPasswordReset: {
lexicon: 1,
id: 'com.atproto.account.requestPasswordReset',
Expand Down Expand Up @@ -3796,6 +3832,7 @@ export const ids = {
ComAtprotoAccountCreateInviteCode: 'com.atproto.account.createInviteCode',
ComAtprotoAccountDelete: 'com.atproto.account.delete',
ComAtprotoAccountGet: 'com.atproto.account.get',
ComAtprotoAccountRequestDelete: 'com.atproto.account.requestDelete',
ComAtprotoAccountRequestPasswordReset:
'com.atproto.account.requestPasswordReset',
ComAtprotoAccountResetPassword: 'com.atproto.account.resetPassword',
Expand Down
22 changes: 21 additions & 1 deletion packages/api/src/client/types/com/atproto/account/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,40 @@ import { lexicons } from '../../../../lexicons'

export interface QueryParams {}

export type InputSchema = undefined
export interface InputSchema {
did: string
password: string
token: string
[k: string]: unknown
}

export interface CallOptions {
headers?: Headers
qp?: QueryParams
encoding: 'application/json'
}

export interface Response {
success: boolean
headers: Headers
}

export class ExpiredTokenError extends XRPCError {
constructor(src: XRPCError) {
super(src.status, src.error, src.message)
}
}

export class InvalidTokenError extends XRPCError {
constructor(src: XRPCError) {
super(src.status, src.error, src.message)
}
}

export function toKnownErr(e: any) {
if (e instanceof XRPCError) {
if (e.error === 'ExpiredToken') return new ExpiredTokenError(e)
if (e.error === 'InvalidToken') return new InvalidTokenError(e)
}
return e
}
27 changes: 27 additions & 0 deletions packages/api/src/client/types/com/atproto/account/requestDelete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* GENERATED CODE - DO NOT MODIFY
*/
import { Headers, XRPCError } from '@atproto/xrpc'
import { ValidationResult } from '@atproto/lexicon'
import { isObj, hasProp } from '../../../../util'
import { lexicons } from '../../../../lexicons'

export interface QueryParams {}

export type InputSchema = undefined

export interface CallOptions {
headers?: Headers
qp?: QueryParams
}

export interface Response {
success: boolean
headers: Headers
}

export function toKnownErr(e: any) {
if (e instanceof XRPCError) {
}
return e
}
7 changes: 7 additions & 0 deletions packages/aws/src/s3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ export class S3BlobStore implements BlobStore {
const res = await this.getObject(cid)
return res as stream.Readable
}

async delete(cid: CID): Promise<void> {
await this.client.deleteObject({
Bucket: this.bucket,
Key: this.getStoredPath(cid),
})
}
}

export default S3BlobStore
3 changes: 2 additions & 1 deletion packages/pds/.prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
src/lexicon/**/*
src/lexicon/**/*
src/mailer/templates/**/*
6 changes: 5 additions & 1 deletion packages/pds/src/api/app/bsky/notification/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ export default function (server: Server, ctx: AppContext) {

let notifBuilder = ctx.db.db
.selectFrom('user_notification as notif')
.innerJoin('ipld_block', 'ipld_block.cid', 'notif.recordCid')
.innerJoin('ipld_block', (join) =>
join
.onRef('ipld_block.cid', '=', 'notif.recordCid')
.onRef('ipld_block.creator', '=', 'notif.author'),
)
.innerJoin('did_handle as author', 'author.did', 'notif.author')
.leftJoin(
'profile as author_profile',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,14 @@ import { InvalidRequestError } from '@atproto/xrpc-server'
import * as crypto from '@atproto/crypto'
import * as handleLib from '@atproto/handle'
import { cidForCbor } from '@atproto/common'
import { Server, APP_BSKY_SYSTEM } from '../../../lexicon'
import { countAll } from '../../../db/util'
import * as lex from '../../../lexicon/lexicons'
import * as repo from '../../../repo'
import { UserAlreadyExistsError } from '../../../services/actor'
import AppContext from '../../../context'
import { Server, APP_BSKY_SYSTEM } from '../../../../lexicon'
import { countAll } from '../../../../db/util'
import * as lex from '../../../../lexicon/lexicons'
import * as repo from '../../../../repo'
import { UserAlreadyExistsError } from '../../../../services/actor'
import AppContext from '../../../../context'

export default function (server: Server, ctx: AppContext) {
server.com.atproto.server.getAccountsConfig(() => {
const availableUserDomains = ctx.cfg.availableUserDomains
const inviteCodeRequired = ctx.cfg.inviteRequired
const privacyPolicy = ctx.cfg.privacyPolicyUrl
const termsOfService = ctx.cfg.termsOfServiceUrl

return {
encoding: 'application/json',
body: {
availableUserDomains,
inviteCodeRequired,
links: { privacyPolicy, termsOfService },
},
}
})

server.com.atproto.account.get(() => {
throw new InvalidRequestError('Not implemented')
})

server.com.atproto.account.create(async ({ input, req }) => {
const { email, password, inviteCode, recoveryKey } = input.body

Expand Down Expand Up @@ -175,9 +155,4 @@ export default function (server: Server, ctx: AppContext) {
},
}
})

server.com.atproto.account.delete(() => {
// TODO
throw new InvalidRequestError('Not implemented')
})
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as crypto from '@atproto/crypto'
import * as uint8arrays from 'uint8arrays'
import { Server } from '../../../lexicon'
import AppContext from '../../../context'
import { Server } from '../../../../lexicon'
import AppContext from '../../../../context'

export default function (server: Server, ctx: AppContext) {
server.com.atproto.account.createInviteCode({
Expand Down
78 changes: 78 additions & 0 deletions packages/pds/src/api/com/atproto/account/delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { AuthRequiredError } from '@atproto/xrpc-server'
import { Server } from '../../../../lexicon'
import AppContext from '../../../../context'
import Database from '../../../../db'

export default function (server: Server, ctx: AppContext) {
server.com.atproto.account.delete(async ({ input }) => {
const { did, password, token } = input.body
const validPass = await ctx.services
.actor(ctx.db)
.verifyUserDidPassword(did, password)
if (!validPass) {
throw new AuthRequiredError('Invalid did or password')
}

const tokenInfo = await ctx.db.db
.selectFrom('did_handle')
.innerJoin('delete_account_token as token', 'token.did', 'did_handle.did')
.where('did_handle.did', '=', did)
.where('token.token', '=', token)
.select([
'token.token as token',
'token.requestedAt as requestedAt',
'token.did as did',
])
.executeTakeFirst()

if (!tokenInfo) {
return createInvalidTokenError()
}

const now = new Date()
const requestedAt = new Date(tokenInfo.requestedAt)
const expiresAt = new Date(requestedAt.getTime() + 15 * minsToMs)
if (now > expiresAt) {
await removeDeleteToken(ctx.db, tokenInfo.did)
return createExpiredTokenError()
}

await ctx.db.transaction(async (dbTxn) => {
await removeDeleteToken(dbTxn, did)
await ctx.services.record(dbTxn).deleteForUser(did)
await ctx.services.repo(dbTxn).deleteRepo(did)
await ctx.services.actor(dbTxn).deleteUser(did)
})
})
}

type ErrorResponse = {
status: number
error: string
message: string
}

const minsToMs = 60 * 1000

const createInvalidTokenError = (): ErrorResponse & {
error: 'InvalidToken'
} => ({
status: 400,
error: 'InvalidToken',
message: 'Token is invalid',
})

const createExpiredTokenError = (): ErrorResponse & {
error: 'ExpiredToken'
} => ({
status: 400,
error: 'ExpiredToken',
message: 'The password reset token has expired',
})

const removeDeleteToken = async (db: Database, did: string) => {
await db.db
.deleteFrom('delete_account_token')
.where('delete_account_token.did', '=', did)
.execute()
}
9 changes: 9 additions & 0 deletions packages/pds/src/api/com/atproto/account/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { InvalidRequestError } from '@atproto/xrpc-server'
import { Server } from '../../../../lexicon'
import AppContext from '../../../../context'

export default function (server: Server, _ctx: AppContext) {
server.com.atproto.account.get(() => {
throw new InvalidRequestError('Not implemented')
})
}
Loading