polkadot-js/apps

View on GitHub
packages/react-hooks/src/useIpfs.ts

Summary

Maintainability
B
4 hrs
Test Coverage
// Copyright 2017-2024 @polkadot/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { useState } from 'react';

import { createNamedHook } from './createNamedHook.js';

const KNOWN = ['ipfs', 'ipns'];
const SECTIONS = KNOWN.map((part) => `/${part}/`);
const LOCAL_IPFS = '.ipfs.localhost';
const LOCAL_IPNS = '.ipns.localhost';

interface State {
  ipnsChain: string | null;
  ipnsDomain: string | null;
  ipfsHash: string | null;
  ipfsPath: string | null;
  isIpfs: boolean;
  isIpns: boolean;
}

function extractLocalIpfs (url: string): State {
  const [,, _ipfsPath] = url.split('/');
  const ipfsPath = _ipfsPath.split(':')[0];

  return {
    ipfsHash: ipfsPath.replace(LOCAL_IPFS, ''),
    ipfsPath,
    ipnsChain: null,
    ipnsDomain: null,
    isIpfs: true,
    isIpns: false
  };
}

function extractLocalIpns (url: string): State {
  const [,, _ipfsPath] = url.split('/');
  const ipfsPath = _ipfsPath.split(':')[0];

  const dnsLink = ipfsPath.replace(LOCAL_IPNS, '');
  const linkParts = dnsLink.split('.');
  let ipnsChain: string | null = null;
  let ipnsDomain: string | null = null;

  if (linkParts.length > 2) {
    ipnsChain = linkParts[0];
    ipnsDomain = linkParts.slice(1).join('.');
  } else {
    ipnsDomain = dnsLink;
  }

  return {
    ipfsHash: null,
    ipfsPath,
    ipnsChain,
    ipnsDomain,
    isIpfs: true,
    isIpns: true
  };
}

function extractOther (url: string): State {
  const isIpfs = SECTIONS.some((part) => url.includes(part));
  const isIpns = url.includes(SECTIONS[1]);

  // individual sections, with the index of the ipfs portion
  const urlParts = url.split('/');
  const index = urlParts.indexOf(isIpns ? KNOWN[1] : KNOWN[0]);

  // the parts of the path for ipfs re-construction
  let ipfsHash: string | null = null;
  let ipfsPath: string | null = null;
  let ipnsChain: string | null = null;
  let ipnsDomain: string | null = null;

  // setup the ipfs part and dnslink domain (if available)
  if (index !== -1) {
    ipfsPath = urlParts.slice(0, index + 1).join('/');

    if (isIpns) {
      const dnsLink = urlParts[index + 1];
      const linkParts = dnsLink.split('.');

      if (linkParts.length > 2) {
        ipnsChain = linkParts[0];
        ipnsDomain = linkParts.slice(1).join('.');
      } else {
        ipnsDomain = dnsLink;
      }
    } else {
      ipfsHash = urlParts[index + 1];
    }
  }

  return {
    ipfsHash,
    ipfsPath,
    ipnsChain,
    ipnsDomain,
    isIpfs,
    isIpns
  };
}

export function extractIpfsDetails (): State {
  // get url and check to see if we are ipfs/ipns
  const [url] = window.location.href.split('#');

  return url.includes(LOCAL_IPFS)
    ? extractLocalIpfs(url)
    : url.includes(LOCAL_IPNS)
      ? extractLocalIpns(url)
      : extractOther(url);
}

function useIpfsImpl (): State {
  const [state] = useState(() => extractIpfsDetails());

  return state;
}

export const useIpfs = createNamedHook('useIpfs', useIpfsImpl);