transform a CID into an RFC6920 URI
Something went wrong. Try again.
cid-to-ni.rb
· Created 4mo ago ·2.5 kB · 77 lines
Ruby
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677#!/usr/bin/env ruby
require 'base32' # you will have to `gem install` thisrequire 'uri/ni' # this too (i wrote it)
# i had claude (sonnet 4.6) initially provide me the basics for these# two functions and then i cleaned up its silliness
# note that's "variable integer" not a typo of "variant"def decode_varint string # don't raise here just return nil return if string.empty?
# first make sure the string is bytes and duplicate it so we don't # hurt the original string = string.b.dup
out = 0 # the return value shift = 0 # 7-bit increments to shift left
loop do # do raise here though because this is actually an error raise ArgumentError, 'malformed varint' if string.empty?
# peel off the first byte and get its ordinal value byte = string.slice!(0).ord # mask, shift left and OR it out |= (byte & 0x7f) << (7 * shift)
# continue only if the high-order bit is set break if (byte & 0x80).zero?
shift += 1 # the other 7 bits are data end
# return the varint and remaining string [out, string]end
def decode_cidv1_base32 cid # first character is the encoding raw = Base32.decode(cid[1..].upcase)
# this will clip the varints off the front of the string version, raw = decode_varint raw codec, raw = decode_varint raw algo, raw = decode_varint raw len, raw = decode_varint raw
# note: # * `version` would dispatch but we only deal with version 1 here # * `codec` tells us something about the thing that was hashed # * `algo` 0x12 is sha-256 so that's hard coded for now # * `len` is the payload length which we hope is fully present # # (see https://github.com/multiformats/multicodec/blob/master/table.csv) # # so we could just imagine mapping that table to hash algorithms and # mime types or whatever
# here have some diagnostics if you like, lol # # warn (["0x%02x (%d)"] * 4).join(', ') % # [version, codec, algo, len].map { |x| [x, x] }.flatten
# oh yeah ruby has base64 built into `pack` b64 = [raw[0, len]].pack('m0').tr('+/', '-_').delete(?=)
# the content-type query parameter accounts for the `codec` component URI("ni:///sha-256;#{b64}?ct=application/vnd.ipld.dag-cbor")end
if $0 == __FILE__ uri = decode_cidv1_base32 'bafyreiemgv3douzgbjnytcp5tbdb4iguk34l3ik2w5ahwnenzehmexdidm' puts uri # ni:///sha-256;jDV2N1MmCluJif2YRh4g1Fb4vaFat0B7NI3JDsJcaBs?ct=application/vnd.ipld.dag-cbor puts uri.hexdigest # 8c35763753260a5b8989fd98461e20d456f8bda15ab7407b348dc90ec25c681bend