fission-suite/webnative

View on GitHub
src/components/auth/implementation/fission/index.ts

Summary

Maintainability
A
40 mins
Test Coverage
import type { Dependencies } from "../base.js"

import * as Crypto from "../../../crypto/implementation.js"
import * as DID from "../../../../did/index.js"
import * as Fission from "../../../../common/fission.js"
import * as Reference from "../../../reference/implementation.js"
import * as Ucan from "../../../../ucan/index.js"

import { USERNAME_BLOCKLIST } from "./blocklist.js"
import { Endpoints } from "../../../../common/fission.js"


export * from "../../../../common/fission.js"


/**
 * Create a user account.
 */
export async function createAccount(
  endpoints: Endpoints,
  dependencies: Dependencies,
  userProps: {
    username: string
    email?: string
  }
): Promise<{ success: boolean }> {
  const jwt = Ucan.encode(await Ucan.build({
    audience: await Fission.did(endpoints),
    dependencies: dependencies,
    issuer: await DID.ucan(dependencies.crypto),
  }))

  const response = await fetch(Fission.apiUrl(endpoints, "/user"), {
    method: "PUT",
    headers: {
      "authorization": `Bearer ${jwt}`,
      "content-type": "application/json"
    },
    body: JSON.stringify(userProps)
  })

  return {
    success: response.status < 300
  }
}


/**
 * Check if a username is available.
 */
export async function isUsernameAvailable(
  endpoints: Endpoints,
  username: string
): Promise<boolean> {
  const resp = await fetch(
    Fission.apiUrl(endpoints, `/user/data/${username}`)
  )

  return !resp.ok
}


/**
 * Check if a username is valid.
 */
export function isUsernameValid(username: string): boolean {
  return !username.startsWith("-") &&
    !username.endsWith("-") &&
    !username.startsWith("_") &&
    /^[a-zA-Z0-9_-]+$/.test(username) &&
    !USERNAME_BLOCKLIST.includes(username.toLowerCase())
}


/**
 * Ask the fission server to send another verification email to the
 * user currently logged in.
 *
 * Throws if the user is not logged in.
 */
export async function resendVerificationEmail(
  endpoints: Endpoints,
  crypto: Crypto.Implementation,
  reference: Reference.Implementation
): Promise<{ success: boolean }> {
  // We've not implemented an "administer account" resource/ucan, so authenticating
  // with any kind of ucan will work server-side
  const localUcan = (await reference.repositories.ucans.getAll())[ 0 ]
  if (localUcan === null) {
    throw "Could not find your local UCAN"
  }

  const jwt = Ucan.encode(await Ucan.build({
    audience: await Fission.did(endpoints),
    dependencies: { crypto },
    issuer: await DID.ucan(crypto),
    proof: localUcan,
    potency: null
  }))

  const response = await fetch(
    Fission.apiUrl(endpoints, "/user/email/resend"),
    {
      method: "POST",
      headers: {
        "authorization": `Bearer ${jwt}`
      }
    }
  )

  return {
    success: response.status < 300
  }
}