#!/usr/bin/env bash
###
### arching-kaos-tools
### Tools to interact and build an Arching Kaos Infochain
### Copyright (C) 2021 - 2025 kaotisk
###
### This program is free software: you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation, either version 3 of the License, or
### (at your option) any later version.
###
### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
### GNU General Public License for more details.
###
### You should have received a copy of the GNU General Public License
### along with this program. If not, see .
###
#set -x
source $AK_LIBDIR/_ak_log
source $AK_LIBDIR/_ak_script
source $AK_LIBDIR/_ak_gpg
source $AK_LIBDIR/_ak_html
source $AK_LIBDIR/_ak_ipfs
if [ ! -d $AK_WORKDIR/ipfs ]
then
mkdir $AK_WORKDIR/ipfs
fi
_ak_data_expand(){
if [ ! -z $1 ] && [ ! -z $2 ] && [ -n "$1" ] && [ -n "$2" ]
then
TEMP="$(_ak_make_temp_directory)"
cd $TEMP
_ak_ipfs_cid_v0_check $1
_ak_ipfs_cat $1 > /dev/null
if [ $? -ne 0 ]
then
_ak_log_error "Error while reading $1"
exit 1
fi
_ak_ipfs_cat $1 | jq -M > /dev/null
if [ $? -ne 0 ]
then
_ak_log_error "Error while parsing JSON for $1"
exit 1
fi
_ak_ipfs_cat $1 | jq | grep ipfs > /dev/null
if [ $? -ne 0 ]
then
_ak_log_error "_ak_data_expand: No 'ipfs' field in $1"
exit 1
fi
DATA="$(_ak_ipfs_cat $1 | jq -r '.ipfs')" #| grep ipfs | sed -e 's/"ipfs": "//g; s/[",]//g; s/ //g')"
if [ $? -ne 0 ]
then
_ak_log_error "Error while extracting data from JSON for $1"
exit 1
fi
_ak_ipfs_cat $1 | jq | grep detach > /dev/null
if [ $? -ne 0 ]
then
_ak_log_error "_ak_data_expand: No 'detach' field in $1"
exit 1
fi
DETACH="$(_ak_ipfs_cat $1 | jq -r '.detach')" #| grep detach | sed -e 's/"detach": "//g; s/[",]//g; s/ //g')"
if [ $? -ne 0 ]
then
_ak_log_error "Error while extracting data from JSON for $1"
exit 1
fi
_ak_ipfs_cid_v0_check $2
gpg="$2"
_ak_ipfs_get $gpg > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "Could not get GPG key: $gpg"
exit 1
fi
_ak_gpg_key_import_from_file $gpg > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "Could not import GPG key: $gpg"
exit 1
fi
_ak_ipfs_get $DETACH > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "Error while getting signature: $DETACH for data: $DATA"
exit 1
fi
if [ ! -f $AK_IPFS_ARTIFACTS/$DETACH ]
then
_ak_log_error "$DETACH was downloaded but not found"
exit 1
fi
ln -s $AK_IPFS_ARTIFACTS/$DETACH $TEMP/$DATA.asc
_ak_log_debug "DATA_SIGNATURE $DETACH downloaded"
_ak_ipfs_get $DATA > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "Error while getting data: $DATA"
exit 1
fi
_ak_log_debug "DATA $DATA downloaded"
_ak_gpg_verify_signature $TEMP/$DATA.asc $AK_IPFS_ARTIFACTS/$DATA # > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "Error while verifying signature for $DATA"
exit 1
fi
# ln -s $AK_IPFS_ARTIFACTS/$DATA $AK_WORKDIR/ipfs
_ak_log_info "DATA_SIGNATURE $DATA_SIGNATURE verified"
echo -n '"data":"'$1'","'$1'":'$(_ak_ipfs_cat $1|jq -M -c)','
cd
# rm -rf $TEMP
else
_ak_log_error "_ak_data_expand HASH GPG"
exit 1
fi
}
# _ak_zblock_show
# ak-zblock [IPFS CID]
#
# Returns a JSON array representing the chain retrieved.
# Logs messages to $LOGSFILE.
_ak_zblock_show(){
verify=1
if [ ! -z $1 ] && [ -n "$1" ]
then
_ak_ipfs_cid_v0_check $1
entrance="$1"
else
entrance="$(cat $AK_ZLATEST)"
fi
TEMP=$(_ak_make_temp_directory)
cd $TEMP
zblock=$entrance
# Check if $zblock exists as variable
if [ ! -v $zblock ]
then
# Check if it is not our seed cause if it is we skip this part
if [ "$zblock" != "$seed" ]
then
# Reset timestamp since it's introduced later
timestamp=''
# Announce to logs which ZBLOCK is being read at the moment
_ak_log_info "Examining $zblock"
_ak_ipfs_cid_v0_check "$zblock"
# We check if any $zblock at all...
# TODO: Eliminate outputing to file since we store all cat/get'ed
# ipfs hashes on local fs.
_ak_ipfs_cat $zblock > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "ZBLOCK $zblock unreachable"
exit 1
fi
_ak_log_debug "ZBLOCK $zblock within reach"
# ...and if it's JSON formated
cat $AK_IPFS_ARTIFACTS/$zblock | jq > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "ZBLOCK $zblock is not JSON"
cat /dev/null > $AK_IPFS_ARTIFACTS/$zblock > /dev/null 2>&1
exit 1
fi
_ak_log_debug "ZBLOCK $zblock is JSON"
echo -n '{'
# echo -n '"id":"'$counter'",'
echo -n '"zblock":"'$zblock'",'
# Be sure that there are the expected values
# We need 'block' and 'block_signature' inside a 'zblock'
# Exit if any is missing
block="$(cat $AK_IPFS_ARTIFACTS/$zblock | jq -M -r .block)"
if [ "$block" == "null" ]
then
_ak_log_error "ZBLOCK $zblock has no BLOCK"
exit 1
fi
_ak_ipfs_cid_v0_check "$block"
_ak_log_debug "ZBLOCK $zblock has block $block"
block_signature="$(cat $AK_IPFS_ARTIFACTS/$zblock | jq -M -r .block_signature)"
if [ "$block_signature" == "null" ]
then
_ak_log_error "ZBLOCK $zblock has no BLOCK_SIGNATURE"
exit 1
fi
_ak_ipfs_cid_v0_check "$block_signature"
_ak_log_debug "ZBLOCK $zblock contains a BLOCK_SIGNATURE $block_signature"
# Same as above applies to BLOCK and DATA subparts of each ZBLOCK
# BLOCKS
echo -n '"block":"'$block'",'
echo -n '"block_signature":"'$block_signature'",'
_ak_ipfs_cat $block | jq -c -M > /dev/null 2>&1
cat $AK_IPFS_ARTIFACTS/$block | jq -M > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "BLOCK $block READ failed"
exit 1
fi
grep -e 'timestamp' -e 'gpg' -e 'data' -e 'action' -e 'detach' -e 'previous' $AK_IPFS_ARTIFACTS/$block > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "BLOCK $block is NOT a valid block"
exit 1
fi
_ak_log_debug "BLOCK $block is a block"
action="$(cat $AK_IPFS_ARTIFACTS/$block | jq -M -r .action)"
module="$(echo $action | sed -e 's/\// /g' | awk '{ print $1 }')"
_ak_log_debug "DATA is $module module."
command="$(echo $action | sed -e 's/\// /g' | awk '{ print $2 }')"
_ak_log_debug "COMMAND is $command"
timestamp="$(cat $AK_IPFS_ARTIFACTS/$block | jq -M -r .timestamp)"
if [ "$timestamp" != "null" ]
then
echo -n '"timestamp":"'$timestamp'",'
fi
detach="$(cat $AK_IPFS_ARTIFACTS/$block | jq -M -r .detach)"
echo -n '"detach":"'$detach'",'
echo -n '"module":"'$module'",'
echo -n '"action":"'$command'",'
gpg="$(cat $AK_IPFS_ARTIFACTS/$block | jq -M -r .gpg)"
echo -n '"gpg":"'$gpg'",'
if [ $verify -eq 1 ]
then
_ak_ipfs_get $gpg > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "Could not get GPG key: $gpg ."
exit 1
fi
_ak_gpg_key_import_from_file $gpg > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "Could not import GPG key: $gpg ."
exit 1
fi
_ak_ipfs_get $block_signature > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "Error while getting BLOCK_SIGNATURE $block_signature for BLOCK $block"
exit 1
fi
ln -s $AK_IPFS_ARTIFACTS/$block_signature $TEMP/$block.asc
_ak_log_info "BLOCK_SIGNATURE $block_signature downloaded"
_ak_ipfs_get $block > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "Could not get $block block"
exit 1
fi
_ak_log_info "BLOCK $block downloaded"
_ak_gpg_verify_signature $TEMP/$block.asc $AK_IPFS_ARTIFACTS/$block > /dev/null 2>&1
if [ $? -ne 0 ]
then
_ak_log_error "Could not verify $block with GPG key $gpg."
exit 1
fi
_ak_log_info "$gpg signature of $block is verified."
fi
data="$(cat $AK_IPFS_ARTIFACTS/$block | jq -M -r .data)"
_ak_ipfs_cid_v0_check "$data"
_ak_data_expand $data $gpg
if [ $? -ne 0 ]
then
_ak_log_error "Failed on data signature verification [data: $data, gpg: $gpg, zblock: $zblock]"
exit 1
fi
# DATA
# Only print to stdout
# _ak_ipfs_cat $data
# touch $AK_DATADIR/$data
# ^ unreasonable?
# Now, since we sourced the BLOCK to our terminal, we can search
# for $previous variable. In case we don't find one, we append one
# and we exit.
previous="$(cat $AK_IPFS_ARTIFACTS/$block | jq -M -r .previous)"
if [ -v $previous ]
then
_ak_log_warning "Block $block has no previous zblock, appending pseudo genesis to exit with 2."
echo -n '"previous":"'$seed'"},{"genesis":"genesis"}]'
_ak_log_info "Reached pseudo-genesis, counted $counter zblocks."
exit 2
# Otherwise, we inform of the sequence
else
#echo "$zblock after $previous"
_ak_log_info "Found a previous block for $zblock: $previous"
echo -n '"previous":"'$previous'"}'
zblock=$previous
fi
# Now check if it is equal to the seed
# which apparently means we reached the seed.
elif [ "$zblock" == "$seed" ]
then
echo -n '{"genesis":"genesis"}]'
_ak_log_info "Reached $seed, counted $counter zblocks."
exit 0
fi
# And finally, if nothing is there exit with error
else
echo "Check not passed... No previous IPFS CID"
exit 1
fi
}
# _ak_zblock_manipulator(){
# # This file describe the structure of the ArchingKaos messages in their basis.
# #
# # As previously thought, we exchange one IPFS hash through whatever means we can.
# #
# # GPG is mentioned as a signing algorithm for encryption, decryption and signing.
# # Let's say we have a file named as `example`
# #
# # We can extend this with calling the encoder and further send the transaction
# #
#
# #FINGERPRINT="CHANGE THIS TO YOUR DEFAULT FINGERPRINT"
# # We acquire the GPG fingerprint by email address
# # The following example finds kaos@kaos.kaos' GPG fingerprint like this
# # FINGERPRINT="$(gpg2 --homedir $AK_GPGHOME --list-keys | grep kaos@kaos.kaos -1 | head -n1 | awk '{print $1}')"
#
# # Below, the usage information
# PROGRAM="$(basename $0)"
# source $AK_LIBDIR/_ak_log
# source $AK_LIBDIR/_ak_ipfs
# source $AK_LIBDIR/_ak_gpg
#
# usage(){
# echo "Usage:"
# echo "$PROGRAM -b block_file | -h block_hash | dunno"
# echo "Creates and publishes a ZBLOCK based on a block and a previous"
# echo "zblock."
# echo ""
# echo "Either -b or -h is needed. If both, -h is used."
# echo ""
# echo "-b block_file Points to a block file that we want to fix."
# echo "-h block_hash If we don't have the block as a file, we can"
# echo " use it's hash to retrieve it and edit it."
# echo "-p previous_hash We refering to a previous hash for a ZBLOCK."
# echo ""
# echo "#TODO:"
# echo "-t timestamp Unix UTC timestamp in seconds."
# echo "-a \"module/action\" Change the action tag. Format: object/verb."
# echo " In sense, \"Add news -> news/add\"."
# echo "-d data In case you want to change the data, you 'll"
# echo " be changing potentially the key of the block"
# echo " and the data signature, otherwise your block"
# echo " will be unverified."
# echo ""
# }
#
# main(){
#
# _ak_log_info "We are doing" $BLOCK_TO_ADD "with content" $PREVIOUS
# # We add it to IPFS
# MESSAGE_HASH=$(_ak_ipfs_add $MESSAGE)
#
# # We create a detached and armor signature of it
# MESSAGE_SIGN_FILE=$MESSAGE".asc"
# _ak_gpg_sign_detached $MESSAGE_SIGN_FILE $MESSAGE
#
# # We add the signature to IPFS
# MESSAGE_SIGNATURE=$(_ak_ipfs_add $MESSAGE_SIGN_FILE)
#
# # We will be using our public key also to put it in the block later
# KEY="gpg.pub"
# _ak_gpg_key_self_export $KEY
# GPG_PUB_KEY=$(_ak_ipfs_add $KEY)
#
# # Acquire last block of information, to chain this one with previous posted
# PREVIOUS=$(_ak_ipfs_files_stat /zlatest | head -n 1)
#
# # We create a block of json like this:
# cat > block < zblock << EOF
# {
# "block":"$BLOCK",
# "block_signature":"$BLOCK_SIGNATURE"
# }
# EOF
# ZBL="zblock"
# # and we add it on IPFS
# ZBLOCK=$(_ak_ipfs_add $ZBL)
# echo $ZBLOCK
# }
#
# if [ ! -z $2 ];
# then
# PWD="$(pwd)"
#
# # We ask which BLOCK is goind to be edited
# BLOCK_TO_ADD="$1"
# # We ask for a ZBLOCK or GENESIS to put in the BLOCK
# PREVIOUS="$2"
#
# _ak_ipfs_cat "$BLOCK_TO_ADD"
# if [ $? == 0 ];
# then
# echo "Nice! We found the block"
# _ak_ipfs_get "$BLOCK_TO_ADD"
#
# sed -i.bak -e 's/^.*previous.*$/\"previous\":\"'$PREVIOUS'\"/' $BLOCK_TO_ADD
# cat $BLOCK_TO_ADD | jq -M
#
# exit 2
# else
# echo "Too bad, it seems the block is not there"
# exit 1
# fi
#
# # cat $PWD/zblock | jq -M
# # Optional or extending with
# # python send_as_ak_tx $ZBLOCK
# # or for "offline" use
# echo $ZBLOCK > $ZLATEST
# _ak_ipfs_name_publish --key=zchain $ZBLOCK > /dev/null 2>&1
# _ak_ipfs_files_mkdir /zarchive > /dev/null 2>&1
# _ak_ipfs_files_cp /zlatest /zarchive/$(date -u +%s)-$(_ak_ipfs_files_stat /zlatest | head -n 1) > /dev/null 2>&1
# _ak_ipfs_files_rm /zlatest > /dev/null 2>&1
# _ak_ipfs_files_cp /ipfs/$ZBLOCK /zlatest > /dev/null 2>&1
# else
# usage
# exit 0
# fi
#
# }
_ak_zblock_gen_html(){
time_started=$(date -u +%s.%N)
ss=$(echo $time_started | cut -d '.' -f 1)
nss=$(echo $time_started | cut -d '.' -f 2)
# Check if there are enough arguments
if [ $# -lt 1 ]
then
_ak_log_error "Not enough arguments provided"
_ak_help
exit 1
fi
if [ -n "$1" ]
then
TEST="$(echo -n "$1" | grep -v '^Qm[A-Za-z0-9]\{44\}$')"
if [ -n "$TEST" ]
then
echo not ok
exit 1
fi
fi
arg="$(_ak_make_temp_file)"
_ak_zblock_show "$1" | jq > $arg
_ak_generate_html_header > zblock-$1.html
_ak_generate_html_zblock $arg >> zblock-$1.html
time_ended=$(date -u +%s.%N)
se=$(echo $time_ended | cut -d '.' -f 1)
nse=$(echo $time_ended | cut -d '.' -f 2)
printf ' \n' >> zblock-$1.html
printf ' \n' "$(( 1$nse - $nss ))" >> zblock-$1.html
else
printf '%s seconds' "$(( $nse - $(echo -n $nss|sed 's/^0*//') ))" >> zblock-$1.html
fi
printf '