Skip to content

Commit

Permalink
Handle package (bluesky-social#305)
Browse files Browse the repository at this point in the history
* handle package

* forgot a couple things

* few more fixes
  • Loading branch information
dholms authored Nov 3, 2022
1 parent 7fdbb4d commit 7ee8213
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 45 deletions.
19 changes: 19 additions & 0 deletions packages/handle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Handle

Validation logic for AT handles

## Usage

```typescript
import * as handle from '@atproto/handle'

isValid('alice.test', ['.test']) // returns true
ensureValid('alice.test', ['.test']) // returns void

isValid('al!ce.test', ['.test']) // returns false
isValid('al!ce.test', ['.test']) // throws
```

## License

MIT
1 change: 1 addition & 0 deletions packages/handle/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../../babel.config.js')
6 changes: 6 additions & 0 deletions packages/handle/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const base = require('../../jest.config.base.js')

module.exports = {
...base,
displayName: 'Handle',
}
20 changes: 20 additions & 0 deletions packages/handle/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@atproto/handle",
"version": "0.0.1",
"main": "src/index.ts",
"scripts": {
"test": "jest",
"prettier": "prettier --check src/",
"prettier:fix": "prettier --write src/",
"lint": "eslint . --ext .ts,.tsx",
"lint:fix": "yarn lint --fix",
"verify": "run-p prettier lint",
"verify:fix": "yarn prettier:fix && yarn lint:fix",
"build": "esbuild src/index.ts --define:process.env.NODE_ENV=\\\"production\\\" --bundle --platform=node --sourcemap --outfile=dist/index.js",
"postbuild": "tsc --build tsconfig.build.json"
},
"license": "MIT",
"dependencies": {
"@sideway/address": "^5.0.0"
}
}
54 changes: 54 additions & 0 deletions packages/handle/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as address from '@sideway/address'
import { reservedSubdomains } from './reserved'

export const ensureValid = (
handle: string,
availableUserDomains: string[],
): void => {
if (handle.startsWith('did:')) {
throw new InvalidHandleError(
'Cannot register a handle that starts with `did:`',
)
}
const supportedDomain = availableUserDomains.find((domain) =>
handle.endsWith(domain),
)
if (!supportedDomain) {
throw new InvalidHandleError('Not a supported handle domain')
}
const front = handle.slice(0, handle.length - supportedDomain.length)
if (front.length < 2) {
throw new InvalidHandleError('Handle too short')
} else if (front.length > 20) {
throw new InvalidHandleError('Handle too long')
}

if (reservedSubdomains[front]) {
throw new InvalidHandleError('Reserved handle')
}

if (front.indexOf('.') > -1) {
throw new InvalidHandleError('Invalid characters in handle')
}

const isValid = address.isDomainValid(handle)
if (!isValid) {
throw new InvalidHandleError('Invalid characters in handle')
}
}
export const isValid = (
handle: string,
availableUserDomains: string[],
): boolean => {
try {
ensureValid(handle, availableUserDomains)
} catch (err) {
if (err instanceof InvalidHandleError) {
return false
}
throw err
}
return true
}

export class InvalidHandleError extends Error {}
File renamed without changes.
34 changes: 34 additions & 0 deletions packages/handle/tests/handle.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ensureValid } from '../src'

describe('handle validation', () => {
const domains = ['.bsky.app', '.test']
const check = (toCheck: string) => () => {
return ensureValid(toCheck, domains)
}

it('allows valid handles', () => {
check('john.test')
check('john.bsky.app')
})
it('errors on invalid handles', () => {
expect(check('did:john.test')).toThrow(
'Cannot register a handle that starts with `did:`',
)
expect(check('john.bsky.io')).toThrow('Not a supported handle domain')
expect(check('john.com')).toThrow('Not a supported handle domain')
expect(check('j.test')).toThrow('Handle too short')
expect(check('jayromy-johnber123456.test')).toThrow('Handle too long')
expect(check('john.test.bsky.app')).toThrow('Invalid characters in handle')
expect(check('john..test')).toThrow('Invalid characters in handle')
expect(check('jo_hn.test')).toThrow('Invalid characters in handle')
expect(check('jo!hn.test')).toThrow('Invalid characters in handle')
expect(check('jo%hn.test')).toThrow('Invalid characters in handle')
expect(check('jo&hn.test')).toThrow('Invalid characters in handle')
expect(check('jo*hn.test')).toThrow('Invalid characters in handle')
expect(check('jo|hn.test')).toThrow('Invalid characters in handle')
expect(check('jo:hn.test')).toThrow('Invalid characters in handle')
expect(check('jo/hn.test')).toThrow('Invalid characters in handle')
expect(check('about.test')).toThrow('Reserved handle')
expect(check('atp.test')).toThrow('Reserved handle')
})
})
4 changes: 4 additions & 0 deletions packages/handle/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["**/*.spec.ts", "**/*.test.ts"]
}
8 changes: 8 additions & 0 deletions packages/handle/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist", // Your outDir,
"emitDeclarationOnly": true
},
"include": ["./src","__tests__/**/**.ts"],
}
2 changes: 1 addition & 1 deletion packages/pds/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
"@atproto/auth": "*",
"@atproto/common": "*",
"@atproto/crypto": "*",
"@atproto/handle": "*",
"@atproto/lexicon": "*",
"@atproto/plc": "*",
"@atproto/repo": "*",
"@atproto/uri": "*",
"@atproto/xrpc-server": "*",
"@hapi/bourne": "^3.0.0",
"@sideway/address": "^5.0.0",
"better-sqlite3": "^7.6.2",
"cors": "^2.8.5",
"dotenv": "^16.0.0",
Expand Down
11 changes: 9 additions & 2 deletions packages/pds/src/api/com/atproto/account.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { InvalidRequestError } from '@atproto/xrpc-server'
import { RepoStructure } from '@atproto/repo'
import { PlcClient } from '@atproto/plc'
import * as handleLib from '@atproto/handle'
import { Server } from '../../../lexicon'
import * as locals from '../../../locals'
import { countAll } from '../../../db/util'
import { UserAlreadyExistsError } from '../../../db'
import SqlBlockstore from '../../../sql-blockstore'
import { ensureValidHandle } from './util/handle'
import { grantRefreshToken } from './util/auth'
import { AtUri } from '@atproto/uri'
import * as schema from '../../../lexicon/schemas'
Expand Down Expand Up @@ -35,7 +35,14 @@ export default function (server: Server) {
const email = input.body.email.toLowerCase()

// throws if not
ensureValidHandle(handle, config.availableUserDomains)
try {
handleLib.ensureValid(handle, config.availableUserDomains)
} catch (err) {
if (err instanceof handleLib.InvalidHandleError) {
throw new InvalidRequestError(err.message, 'InvalidHandle')
}
throw err
}

const now = new Date().toISOString()

Expand Down
42 changes: 0 additions & 42 deletions packages/pds/src/api/com/atproto/util/handle.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/pds/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
{ "path": "../auth/tsconfig.build.json" },
{ "path": "../common/tsconfig.build.json" },
{ "path": "../crypto/tsconfig.build.json" },
{ "path": "../handle/tsconfig.build.json" },
{ "path": "../lexicon/tsconfig.build.json" },
{ "path": "../lex-cli/tsconfig.build.json" },
{ "path": "../plc/tsconfig.build.json" },
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
{ "path": "./packages/crypto/tsconfig.build.json" },
{ "path": "./packages/dev-env" },
{ "path": "./packages/did-resolver/tsconfig.build.json" },
{ "path": "./packages/handle/tsconfig.build.json" },
{ "path": "./packages/lexicon/tsconfig.build.json" },
{ "path": "./packages/lex-cli/tsconfig.build.json" },
{ "path": "./packages/nsid/tsconfig.build.json" },
Expand Down

0 comments on commit 7ee8213

Please sign in to comment.