Skip to content

Commit

Permalink
base-files: add sysupgrade-online script as POC
Browse files Browse the repository at this point in the history
This is a proof of conecpt and requires further work, it show how a
device can find upgrades only in a secure way, without any extra
packages, especially nothing HTTPS related.

The online.sh "library" can be used for CLIs or ubus calls for Luci or
other webinterfaces to come.

Details about the JSON structure are explained in another PR[0].

To try the script, run `sysupgrade-online --search` or `--unattended`,
the former searches for a sysupgrade (only snapshots currently), the
latter searches and passes results to a download function, which then
downloaded the sysupgrade.

Ideally the sysupgrade would be verified aditionally via usign.

[0]: openwrt#2192

Signed-off-by: Paul Spooren <mail@aparcar.org>
  • Loading branch information
aparcar committed Sep 1, 2019
1 parent 0cc87b3 commit b04f791
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 0 deletions.
20 changes: 20 additions & 0 deletions package/base-files/files/bin/sysupgrade-online
@@ -0,0 +1,20 @@
#!/bin/sh

# POC to simplify sysupgrade via JSON info files
# based on https://github.com/openwrt/openwrt/pull/2192

. /lib/upgrade/online.sh

while [ -n "$1" ]; do
case "$1" in
-s|--search) sysupgrade_search;;
-d|--download) sysupgrade_download;;
-u|--unattended) sysupgrade_unattended;;
-*)
echo "Invalid option: $1" >&2
exit 1
;;
*) break;;
esac
shift;
done
151 changes: 151 additions & 0 deletions package/base-files/files/lib/upgrade/online.sh
@@ -0,0 +1,151 @@
#!/bin/sh

. /usr/share/libubox/jshn.sh
. /etc/openwrt_release

# later to be http://downloads.openwrt.org
# find public key at $UPDATE_SERVER/key-build.pub
UPDATE_SERVER="http://update.aparcar.stephen304.com/download/json-demo/openwrt"

# downloads file and check if sha256sum matches
download_and_check() {
# $1 URL to download
# $2 sha256sum
rm -f "$(basename $1)"
wget "$1" || exit 1
if [[ "$(sha256sum $(basename $1) | cut -d ' ' -f 1)" != "$2" ]]; then
>&2 echo "$(basename $1): bad checksum"
>&2 echo "URL: $1"
>&2 echo "expected: $2"
exit 1
fi
}

# strip revision to a comparable integer
revision_count() {
# $1 revision commit
echo "$1" | cut -d "-" -f 0 | cut -d "+" -f 0 | tail -c +2
}

# check if found version is upgrdable
# TODO: currently only checks snapshots for newer revision
upgradable() {
version="$1"
revision="$2"
if [[ "$version" == "SNAPSHOT" -a "$DISTRIB_RELEASE" == "SNAPSHOT" ]]; then
if [[ $(revision_count $revision) -gt $(revision_count $DISTRIB_REVISION) ]]; then
>&2 echo "SNAPSHOT upgrade to $revision found"
echo 1
fi
fi
}

# searches for new sysupgrades
sysupgrade_search() {
cd /tmp && {
rm versions.json*
wget "$UPDATE_SERVER/versions.json"
wget "$UPDATE_SERVER/versions.json.sig"
usign -V -P /etc/opkg/keys -m versions.json || {
echo "versions.json: bad usign signature"
exit 1
}

json_load_file versions.json
json_get_var metadata_version metadata_version
json_select versions

idx="1"
while json_get_type Type "$idx" && [ "$Type" == object ]; do
json_select "$idx"
json_get_vars name revision
if [[ -n "$(upgradable $name $revision)" ]]; then
json_get_vars path sha256

json_init
json_add_string name "$name"
json_add_string path "$path"
json_add_string revision "$revision"
json_add_string sha256 "$sha256"
json_dump
exit 0
fi
json_select ..
$((idx++)) 2> /dev/null
done
json_init
json_dump
}
}

# find sysupgrade file for board
sysupgrade_download() {
cd /tmp && {
path_version="$1"
sha256_targets="$2"
json_load "$(ubus call system board)"
json_get_vars board_name
#board_name="zbtlink,zbt-wd323"
download_and_check "$UPDATE_SERVER/$path_version/targets.json" "$sha256_targets"

json_load_file targets.json
json_get_var metadata_version metadata_version
json_select targets
json_select "$DISTRIB_TARGET"
#json_select "ath79/generic"
json_get_var path_target path
json_get_var sha256 sha256

download_and_check "$UPDATE_SERVER/$path_version/$path_target/map.json" "$sha256"

json_load_file "map.json"
json_select devices
json_select "$board_name"
json_get_vars info sha256

download_and_check "$UPDATE_SERVER/$path_version/$path_target/$info" "$sha256"

json_load_file "$info"
json_select "images"

idx="1"
while json_get_type Type "$idx" && [ "$Type" == object ]; do
json_select "$idx"
json_get_var type type
[[ "$type" == "sysupgrade" ]] && break
json_select ..
$((idx++)) 2> /dev/null
done

json_get_var sysupgrade name
json_get_var sha256 sha256

download_and_check "$UPDATE_SERVER/$path_version/$path_target/$sysupgrade" "$sha256"

json_init
json_add_int "successful" 1
json_add_string "firmware" "$sysupgrade"
json_close_object
json_dump
}
}

# combines search, download and sysupgrade
sysupgrade_unattended() {
search_response="$(sysupgrade_search)"
if [[ "$search_response" != "{ }" ]]; then
json_load "$search_response"
json_get_vars path sha256
download_response="$(sysupgrade_download $path $sha256)"
json_load "$download_response"
json_get_vars successful firmware
if [[ "$successful" -gt 0 ]]; then
# TODO don't to anything really
sysupgrade -T "$firmware"
fi
exit $?
else
>&2 echo "No sysupgrade found"
exit 0
fi
}

0 comments on commit b04f791

Please sign in to comment.