Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | 3x 3x 2x 3x 2x 2x 2x 2x 2x 2x 3x 2x 2x 2x 2x 3x 3x 3x 2x 2x 2x 2x 2x 2x 2x 3x | import { getRandomBytes, TokenSigner, privateKeyToBase58Address, Json } from 'micro-stacks/crypto';
import { bytesToHex, fetchPrivate } from 'micro-stacks/common';
import { getPublicKey } from 'micro-stacks/crypto';
import type {
  GaiaHubConfig,
  GaiaAuthScope,
  HubInfo,
  ScopedGaiaTokenOptions,
  GenerateGaiaHubConfigOptions,
} from './types';
 
/**
 * Gaia takes the key 'domain' but 'path' makes more sense to someone implementing this
 */
function transformScopePath(scopes?: GaiaAuthScope[]) {
  return scopes?.map(scope => ({ ...scope, domain: scope.path })) ?? null;
}
 
function makeDefaultScope(path: string): GaiaAuthScope {
  return {
    scope: 'putFilePrefix',
    path,
  };
}
 
export function makeScopedGaiaAuthTokenPayload(options: ScopedGaiaTokenOptions): Json {
  const { hubInfo, privateKey, gaiaHubUrl, associationToken = null, scopes } = options;
  const { challenge_text: gaiaChallenge } = hubInfo;
  const iss = bytesToHex(getPublicKey(privateKey, true));
 
  const salt = getRandomBytes(16).toString();
  const payload: Json = {
    gaiaChallenge,
    hubUrl: gaiaHubUrl,
    iss,
    salt,
    associationToken,
    scopes: transformScopePath(scopes),
  };
  return payload;
}
 
/**
 * Generate a scoped gaia auth token
 */
 
export async function makeScopedGaiaAuthToken(options: ScopedGaiaTokenOptions): Promise<string> {
  const payload = makeScopedGaiaAuthTokenPayload(options);
  const signer = new TokenSigner('ES256K', options.privateKey);
  const token = await signer.sign(payload);
  return `v1:${token}`;
}
 
export function makeScopedGaiaAuthTokenSync(options: ScopedGaiaTokenOptions): string {
  const payload = makeScopedGaiaAuthTokenPayload(options);
  const signer = new TokenSigner('ES256K', options.privateKey);
  const token = signer.signSync(payload);
  return `v1:${token}`;
}
 
const DEFAULT_PAYLOAD: HubInfo = {
  challenge_text: '["gaiahub","0","storage2.blockstack.org","blockstack_storage_please_sign"]',
  latest_auth_version: 'v1',
  max_file_upload_size_megabytes: 20,
  read_url_prefix: 'https://gaia.blockstack.org/hub/',
};
 
/**
 * Generates a gaia hub config to share with someone so they can edit a file
 */
export async function generateGaiaHubConfig(
  options: GenerateGaiaHubConfigOptions,
  fetchHubInfo = false
): Promise<GaiaHubConfig> {
  const { gaiaHubUrl, privateKey, associationToken, scopes } = options;
  let hubInfo = DEFAULT_PAYLOAD;
 
  Iif (fetchHubInfo) {
    const response = await fetchPrivate(`${gaiaHubUrl}/hub_info`);
    hubInfo = await response.json();
  }
 
  const { read_url_prefix: url_prefix, max_file_upload_size_megabytes } = hubInfo;
 
  const token = await makeScopedGaiaAuthToken({
    hubInfo,
    privateKey,
    gaiaHubUrl,
    associationToken,
    scopes,
  });
 
  const address = privateKeyToBase58Address(privateKey);
 
  return {
    address,
    url_prefix,
    token,
    server: gaiaHubUrl,
    max_file_upload_size_megabytes: max_file_upload_size_megabytes ?? 20,
  };
}
 
// sync version
export function generateGaiaHubConfigSync(options: GenerateGaiaHubConfigOptions): GaiaHubConfig {
  const { gaiaHubUrl, privateKey, associationToken, scopes } = options;
  const hubInfo = DEFAULT_PAYLOAD;
 
  const { read_url_prefix: url_prefix, max_file_upload_size_megabytes } = hubInfo;
 
  const token = makeScopedGaiaAuthTokenSync({
    hubInfo,
    privateKey,
    gaiaHubUrl,
    associationToken,
    scopes,
  });
 
  const address = privateKeyToBase58Address(privateKey);
 
  return {
    address,
    url_prefix,
    token,
    server: gaiaHubUrl,
    max_file_upload_size_megabytes: max_file_upload_size_megabytes ?? 20,
  };
}
  |