aboutsummaryrefslogtreecommitdiff
path: root/upload_amo.sh
blob: 4aff80e3553f1719dfcbfe6c9789a7a9fba0dacd (plain)
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
130
131
132
#!/bin/sh

# This file is part of Haketilo
#
# Copyright (C) 2021, Wojtek Kosior
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the CC0 1.0 Universal License as published by
# the Creative Commons Corporation.
#
# 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
# CC0 1.0 Universal License for more details.

set -e

_PROG_NAME="$0"
OPERATION="$1"
API_KEY="$2"
SECRET="$3"
XPI_PATH="$4"

escape_regex_special() {
    printf %s "$1" | sed 's/\([]\.*[-]\)/\\\1/g'
}

# Note: We don't actually parse JSON. We extract needed keys with sed regexes
# which does not work in the general case but is sufficient for now.
_get_json_key() {
    local KEY_REG="$(escape_regex_special "$1")"
    printf %s "$2" |
	awk '{printf "%s", $0}' |
	sed 's/^.*\("'"$KEY_REG"'"[[:space:]]*:[[:space:]]*"\([^"]*\)"\).*$/\2/'
}

get_json_key() {
    local JSON="$2"
    local VALUE="$(_get_json_key "$@")"
    if [ "x$VALUE" != "x$JSON" ]; then
	printf %s "$VALUE"
    fi
}

base64url() {
    printf %s "$1" | base64 -w 0 | tr '/+' '_-' | tr -d '='
}

sha256hmac() {
    base64url "$(printf %s "$2" | openssl dgst -sha256 -hmac "$1" -binary -)"
}

get_manifest_key() {
    get_json_key "$1" "$(unzip -p "$2" manifest.json)"
}

generate_jwt() {
    local JWT_HEAD='{"alg":"HS256", "typ":"JWT"}'
    local JWT_ID=$(dd if=/dev/random bs=21 count=1 2>/dev/null | base64)
    local ISSUED_AT_TIME=$(date -u +%s)
    local EXPIRATION_TIME=$((ISSUED_AT_TIME + 300))
    local JWT_PAYLOAD="$(cat <<EOF
{
    "iss": "$API_KEY",
    "jti": "$JWT_ID",
    "iat": $ISSUED_AT_TIME,
    "exp": $EXPIRATION_TIME
}
EOF
	  )"
    local JWT_MESSAGE=$(base64url "$JWT_HEAD").$(base64url "$JWT_PAYLOAD")
    local JWT_SIGNATURE=$(sha256hmac "$SECRET" "$JWT_MESSAGE")
    local JWT=$JWT_MESSAGE.$JWT_SIGNATURE
    printf "Using JWT: $JWT\n" >&2
    printf $JWT
}

get_extension_url() {
    EXTENSION_ID="$(get_manifest_key id "$XPI_PATH")"
    EXTENSION_VER="$(get_manifest_key version "$XPI_PATH")"

    if [ -z "$EXTENSION_ID" -o -z "$EXTENSION_VER" ]; then
	printf "Couldn't extract extension id and version. Please check if %s contains proper manifest.json file.\n" \
	       "$XPI_PATH" >&2
	exit 1
    fi

    printf 'https://addons.mozilla.org/api/v4/addons/%s/versions/%s/' \
	   "$EXTENSION_ID" "$EXTENSION_VER"
}

print_usage() {
    printf 'Usage:  %s upload|check|test API_KEY SECRET XPI_PATH\n' \
	   "$_PROG_NAME" >&2
}

if [ $# != 4 ]; then
    print_usage
    exit 1
fi

unset RETURNED_DATA

case "$OPERATION" in
    test)
	curl "https://addons.mozilla.org/api/v4/accounts/profile/" \
	     -g -H "Authorization: JWT $(generate_jwt)"
	printf '\n'
	;;
    check)
	RETURNED_DATA="$(curl $(get_extension_url) \
			      -g -H "Authorization: JWT $(generate_jwt)")"
	;;
    upload)
	RETURNED_DATA="$(curl $(get_extension_url) \
			      -g -XPUT --form "upload=@$XPI_PATH" \
			      -H "Authorization: JWT $(generate_jwt)")"
	;;
    *)
	print_usage
	exit 1
	;;
esac

if [ -n "$RETURNED_DATA" ]; then
    printf "addons.mozilla.org says:\n%s\n" "$RETURNED_DATA"
    DOWNLOAD_URL="$(get_json_key download_url "$RETURNED_DATA")"
    if [ -n "$DOWNLOAD_URL" ]; then
	printf "Downloading extension file from %s\n" "$DOWNLOAD_URL"
	curl "$DOWNLOAD_URL" -g -H "Authorization: JWT $(generate_jwt)" -O
    fi
fi