_1password-gui: Add passthru.updateScript (#416072)
This commit is contained in:
@@ -30,4 +30,6 @@ stdenv.mkDerivation {
|
||||
|
||||
# 1Password is notarized.
|
||||
dontFixup = true;
|
||||
|
||||
passthru.updateScript = ./update.sh;
|
||||
}
|
||||
|
||||
@@ -153,4 +153,6 @@ stdenv.mkDerivation {
|
||||
# https://1password.community/discussion/comment/624011/#Comment_624011
|
||||
#--add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime=true}}"
|
||||
'';
|
||||
|
||||
passthru.updateScript = ./update.sh;
|
||||
}
|
||||
|
||||
@@ -11,18 +11,18 @@
|
||||
let
|
||||
pname = "1password";
|
||||
|
||||
versions = builtins.fromJSON (builtins.readFile ./versions.json);
|
||||
hostOs = if stdenv.hostPlatform.isLinux then "linux" else "darwin";
|
||||
version = versions."${channel}-${hostOs}" or (throw "unknown channel-os ${channel}-${hostOs}");
|
||||
|
||||
hostOs = stdenv.hostPlatform.parsed.kernel.name;
|
||||
hostArch = stdenv.hostPlatform.parsed.cpu.name;
|
||||
sources = builtins.fromJSON (builtins.readFile ./sources.json);
|
||||
|
||||
sourcesChan = sources.${channel} or (throw "unsupported channel ${channel}");
|
||||
sourcesChanOs = sourcesChan.${hostOs} or (throw "unsupported OS ${hostOs}");
|
||||
sourcesChanOsArch =
|
||||
sourcesChanOs.sources.${hostArch} or (throw "unsupported architecture ${hostArch}");
|
||||
|
||||
inherit (sourcesChanOs) version;
|
||||
src = fetchurl {
|
||||
inherit
|
||||
(sources.${channel}.${stdenv.system} or (throw "unsupported system ${stdenv.hostPlatform.system}"))
|
||||
url
|
||||
hash
|
||||
;
|
||||
inherit (sourcesChanOsArch) url hash;
|
||||
};
|
||||
|
||||
meta = {
|
||||
@@ -37,7 +37,12 @@ let
|
||||
sebtm
|
||||
bdd
|
||||
];
|
||||
platforms = builtins.attrNames sources.${channel};
|
||||
platforms = [
|
||||
"x86_64-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-linux"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
mainProgram = "1password";
|
||||
};
|
||||
|
||||
|
||||
@@ -1,38 +1,58 @@
|
||||
{
|
||||
"stable": {
|
||||
"x86_64-linux": {
|
||||
"url": "https://downloads.1password.com/linux/tar/stable/x86_64/1password-8.10.78.x64.tar.gz",
|
||||
"hash": "sha256-COmXSjbCetPsbm40OrWGVtULPheEgnHEO0ZcIgWaG1w="
|
||||
"linux": {
|
||||
"version": "8.10.78",
|
||||
"sources": {
|
||||
"x86_64": {
|
||||
"url": "https://downloads.1password.com/linux/tar/stable/x86_64/1password-8.10.78.x64.tar.gz",
|
||||
"hash": "sha256-COmXSjbCetPsbm40OrWGVtULPheEgnHEO0ZcIgWaG1w="
|
||||
},
|
||||
"aarch64": {
|
||||
"url": "https://downloads.1password.com/linux/tar/stable/aarch64/1password-8.10.78.arm64.tar.gz",
|
||||
"hash": "sha256-diy7VhKRluSnVSR35Ogamf9RDHdqxSJifLOOYmMrJHE="
|
||||
}
|
||||
}
|
||||
},
|
||||
"aarch64-linux": {
|
||||
"url": "https://downloads.1password.com/linux/tar/stable/aarch64/1password-8.10.78.arm64.tar.gz",
|
||||
"hash": "sha256-diy7VhKRluSnVSR35Ogamf9RDHdqxSJifLOOYmMrJHE="
|
||||
},
|
||||
"x86_64-darwin": {
|
||||
"url": "https://downloads.1password.com/mac/1Password-8.10.78-x86_64.zip",
|
||||
"hash": "sha256-8fbjEc/Z0xCdXq/uHp4bQE5Js5hNLbVCRZxnepUdLUs="
|
||||
},
|
||||
"aarch64-darwin": {
|
||||
"url": "https://downloads.1password.com/mac/1Password-8.10.78-aarch64.zip",
|
||||
"hash": "sha256-x03dZ/eVrvFcbese1cBAvyJKwtWe6rOcgytn0OsEFDQ="
|
||||
"darwin": {
|
||||
"version": "8.10.78",
|
||||
"sources": {
|
||||
"x86_64": {
|
||||
"url": "https://downloads.1password.com/mac/1Password-8.10.78-x86_64.zip",
|
||||
"hash": "sha256-8fbjEc/Z0xCdXq/uHp4bQE5Js5hNLbVCRZxnepUdLUs="
|
||||
},
|
||||
"aarch64": {
|
||||
"url": "https://downloads.1password.com/mac/1Password-8.10.78-aarch64.zip",
|
||||
"hash": "sha256-x03dZ/eVrvFcbese1cBAvyJKwtWe6rOcgytn0OsEFDQ="
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"beta": {
|
||||
"x86_64-linux": {
|
||||
"url": "https://downloads.1password.com/linux/tar/beta/x86_64/1password-8.10.80-18.BETA.x64.tar.gz",
|
||||
"hash": "sha256-X2Wu/dQQ7fv+tTAU2/70S38wL6WdJuc/DXWoiHZvSP4="
|
||||
"linux": {
|
||||
"version": "8.10.80-18.BETA",
|
||||
"sources": {
|
||||
"x86_64": {
|
||||
"url": "https://downloads.1password.com/linux/tar/beta/x86_64/1password-8.10.80-18.BETA.x64.tar.gz",
|
||||
"hash": "sha256-X2Wu/dQQ7fv+tTAU2/70S38wL6WdJuc/DXWoiHZvSP4="
|
||||
},
|
||||
"aarch64": {
|
||||
"url": "https://downloads.1password.com/linux/tar/beta/aarch64/1password-8.10.80-18.BETA.arm64.tar.gz",
|
||||
"hash": "sha256-52aRg6QD/fKOzOHoG88q8VNJIizxnISFnpxek7bJ05w="
|
||||
}
|
||||
}
|
||||
},
|
||||
"aarch64-linux": {
|
||||
"url": "https://downloads.1password.com/linux/tar/beta/aarch64/1password-8.10.80-18.BETA.arm64.tar.gz",
|
||||
"hash": "sha256-52aRg6QD/fKOzOHoG88q8VNJIizxnISFnpxek7bJ05w="
|
||||
},
|
||||
"x86_64-darwin": {
|
||||
"url": "https://downloads.1password.com/mac/1Password-8.10.80-18.BETA-x86_64.zip",
|
||||
"hash": "sha256-kUU+nm19DmdY8ZG6d+EJFQXcCy/BOauXh83suQLSvz0="
|
||||
},
|
||||
"aarch64-darwin": {
|
||||
"url": "https://downloads.1password.com/mac/1Password-8.10.80-18.BETA-aarch64.zip",
|
||||
"hash": "sha256-eZG0QaB5NRwRCYcmlfZA/HTceLq7eUzR+AvzDeOrzAY="
|
||||
"darwin": {
|
||||
"version": "8.10.80-18.BETA",
|
||||
"sources": {
|
||||
"x86_64": {
|
||||
"url": "https://downloads.1password.com/mac/1Password-8.10.80-18.BETA-x86_64.zip",
|
||||
"hash": "sha256-kUU+nm19DmdY8ZG6d+EJFQXcCy/BOauXh83suQLSvz0="
|
||||
},
|
||||
"aarch64": {
|
||||
"url": "https://downloads.1password.com/mac/1Password-8.10.80-18.BETA-aarch64.zip",
|
||||
"hash": "sha256-eZG0QaB5NRwRCYcmlfZA/HTceLq7eUzR+AvzDeOrzAY="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i python3 -p python3 gnupg
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from collections import OrderedDict
|
||||
|
||||
DOWNLOADS_BASE_URL = "https://downloads.1password.com"
|
||||
OP_PGP_KEYID = "3FEF9748469ADBE15DA7CA80AC2D62742012EA22"
|
||||
|
||||
|
||||
class Sources(OrderedDict):
|
||||
def __init__(self):
|
||||
self._jsonfp = open("sources.json", "r+")
|
||||
self.update(json.load(self._jsonfp))
|
||||
self._jsonfp.seek(0, os.SEEK_SET)
|
||||
|
||||
def persist(self):
|
||||
json.dump(self, self._jsonfp, indent=2)
|
||||
self._jsonfp.write("\n") # keep fmt.check happy
|
||||
|
||||
|
||||
class GPG:
|
||||
def __new__(cls):
|
||||
if not hasattr(cls, "_instance"):
|
||||
cls._instance = super().__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def __init__(self):
|
||||
if hasattr(self, "gnupghome"):
|
||||
return
|
||||
|
||||
self.gpg = shutil.which("gpg")
|
||||
self.gpgv = shutil.which("gpgv")
|
||||
self.gnupghome = tempfile.mkdtemp(prefix="1password-gui-gnupghome.")
|
||||
self.env = {"GNUPGHOME": self.gnupghome}
|
||||
self._run(
|
||||
self.gpg,
|
||||
"--no-default-keyring",
|
||||
"--keyring",
|
||||
"trustedkeys.kbx",
|
||||
"--keyserver",
|
||||
"keyserver.ubuntu.com",
|
||||
"--receive-keys",
|
||||
OP_PGP_KEYID,
|
||||
)
|
||||
|
||||
def __del__(self):
|
||||
shutil.rmtree(self.gnupghome)
|
||||
|
||||
def _run(self, *args):
|
||||
try:
|
||||
subprocess.run(args, env=self.env, check=True, capture_output=True)
|
||||
except subprocess.CalledProcessError as cpe:
|
||||
print(cpe.stderr, file=sys.stderr)
|
||||
raise SystemExit(f"gpg error: {cpe.cmd}")
|
||||
|
||||
def verify(self, sigfile, datafile):
|
||||
return self._run(self.gpgv, sigfile, datafile)
|
||||
|
||||
|
||||
def nix_store_prefetch(url):
|
||||
nix = shutil.which("nix")
|
||||
cp = subprocess.run(
|
||||
[nix, "store", "prefetch-file", "--json", url], check=True, capture_output=True
|
||||
)
|
||||
out = json.loads(cp.stdout)
|
||||
|
||||
return out["storePath"], out["hash"]
|
||||
|
||||
|
||||
def mk_url(channel, os, version, arch):
|
||||
if os == "linux":
|
||||
arch_alias = {"x86_64": "x64", "aarch64": "arm64"}[arch]
|
||||
path = f"linux/tar/{channel}/{arch}/1password-{version}.{arch_alias}.tar.gz"
|
||||
elif os == "darwin":
|
||||
path = f"mac/1Password-{version}-{arch}.zip"
|
||||
else:
|
||||
raise SystemExit(f"update-sources.py: unsupported OS {os}")
|
||||
|
||||
return f"{DOWNLOADS_BASE_URL}/{path}"
|
||||
|
||||
|
||||
def download(channel, os, version, arch):
|
||||
url = mk_url(channel, os, version, arch)
|
||||
store_path_tarball, hash = nix_store_prefetch(url)
|
||||
|
||||
# Linux release tarballs come with detached PGP signatures.
|
||||
if os == "linux":
|
||||
store_path_sig, _ = nix_store_prefetch(url + ".sig")
|
||||
GPG().verify(store_path_sig, store_path_tarball)
|
||||
|
||||
return url, hash
|
||||
|
||||
|
||||
def main(args):
|
||||
"""Gets called with args in `channel/os/version` format.
|
||||
|
||||
e.g.:
|
||||
update-sources.py stable/linux/8.10.80 beta/linux/8.10.82-12.BETA
|
||||
"""
|
||||
sources = Sources()
|
||||
|
||||
for triplet in args[1:]:
|
||||
channel, os, version = triplet.split("/")
|
||||
release = sources[channel][os]
|
||||
if release["version"] == version:
|
||||
continue
|
||||
|
||||
release["version"] = version
|
||||
for arch in release["sources"]:
|
||||
url, hash = download(channel, os, version, arch)
|
||||
release["sources"][arch].update({"url": url, "hash": hash})
|
||||
|
||||
sources.persist()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main(sys.argv))
|
||||
@@ -1,84 +1,118 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p jq gnupg
|
||||
#!nix-shell -i bash -p jq curl
|
||||
#shellcheck shell=bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# For Linux version checks we rely on Repology API to check 1Password managed Arch User Repository.
|
||||
REPOLOGY_PROJECT_URI="https://repology.org/api/v1/project/1password"
|
||||
|
||||
# For Darwin version checks we query the same endpoint 1Password 8 for Mac queries.
|
||||
# This is the base URI. For stable channel an additional path of "N", for beta channel, "Y" is required.
|
||||
APP_UPDATES_URI_BASE="https://app-updates.agilebits.com/check/2/99/aarch64/OPM8/en/0/A1"
|
||||
|
||||
CURL=(
|
||||
"curl" "--silent" "--show-error" "--fail"
|
||||
"--proto" "=https" # enforce https
|
||||
"--tlsv1.2" # do not accept anything below tls 1.2
|
||||
"-H" "user-agent: nixpkgs#_1password-gui update.sh" # repology requires a descriptive user-agent
|
||||
)
|
||||
|
||||
JQ=(
|
||||
"jq"
|
||||
"--raw-output"
|
||||
"--exit-status" # exit non-zero if no output is produced
|
||||
)
|
||||
|
||||
|
||||
read_local_versions() {
|
||||
local channel="$1"
|
||||
|
||||
while IFS='=' read -r key value; do
|
||||
local_versions["${key}"]="${value}"
|
||||
done < <(jq -r --arg channel "${channel}" '
|
||||
.[$channel] | to_entries[] | .key as $os | .value.version as $version |
|
||||
"\($channel)/\($os)=\($version)"
|
||||
' sources.json)
|
||||
}
|
||||
|
||||
read_remote_versions() {
|
||||
local channel="$1"
|
||||
|
||||
if [[ ${channel} == "stable" ]]; then
|
||||
remote_versions["stable/linux"]=$(
|
||||
"${CURL[@]}" "${REPOLOGY_PROJECT_URI}" \
|
||||
| "${JQ[@]}" '.[] | select(.repo == "aur" and .srcname == "1password" and .status == "newest") | .version'
|
||||
)
|
||||
|
||||
remote_versions["stable/darwin"]=$(
|
||||
"${CURL[@]}" "${APP_UPDATES_URI_BASE}/N" \
|
||||
| "${JQ[@]}" 'select(.available == "1") | .version'
|
||||
)
|
||||
else
|
||||
remote_versions["beta/linux"]=$(
|
||||
# AUR version string uses underscores instead of dashes for betas.
|
||||
# We fix that with a `sub` in jq query.
|
||||
"${CURL[@]}" "${REPOLOGY_PROJECT_URI}" \
|
||||
| "${JQ[@]}" '.[] | select(.repo == "aur" and .srcname == "1password-beta") | .version | sub("_"; "-")'
|
||||
)
|
||||
|
||||
remote_versions["beta/darwin"]=$(
|
||||
"${CURL[@]}" "${APP_UPDATES_URI_BASE}/Y" \
|
||||
| "${JQ[@]}" 'select(.available == "1") | .version'
|
||||
)
|
||||
fi
|
||||
}
|
||||
|
||||
render_versions_json() {
|
||||
local key value
|
||||
|
||||
for key in "${!local_versions[@]}"; do
|
||||
value="${local_versions[${key}]}"
|
||||
echo "${key}"
|
||||
echo "${value}"
|
||||
done \
|
||||
| jq -nR 'reduce inputs as $i ({}; . + { $i: input })'
|
||||
}
|
||||
|
||||
|
||||
cd -- "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
mk_url() {
|
||||
local \
|
||||
base_url="https://downloads.1password.com" \
|
||||
os="$1" \
|
||||
channel="$2" \
|
||||
arch="$3" \
|
||||
version="$4"
|
||||
attr_path=${UPDATE_NIX_ATTR_PATH}
|
||||
case "${attr_path}" in
|
||||
_1password-gui) channel="stable" ;;
|
||||
_1password-gui-beta) channel="beta" ;;
|
||||
*)
|
||||
echo "Unknown attribute path ${attr_path}" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
if [[ ${os} == "linux" ]]; then
|
||||
if [[ ${arch} == "x86_64" ]]; then
|
||||
ext="x64.tar.gz"
|
||||
else
|
||||
ext="arm64.tar.gz"
|
||||
fi
|
||||
url="${base_url}/${os}/tar/${channel}/${arch}/1password-${version}.${ext}"
|
||||
else
|
||||
ext="${arch}.zip"
|
||||
url="${base_url}/mac/1Password-${version}-${ext}"
|
||||
declare -A local_versions remote_versions
|
||||
declare -a new_version_available=()
|
||||
read_local_versions "${channel}"
|
||||
read_remote_versions "${channel}"
|
||||
for i in "${!remote_versions[@]}"; do
|
||||
if [[ "${local_versions[$i]}" != "${remote_versions[$i]}" ]]; then
|
||||
old_version="${local_versions[$i]}"
|
||||
new_version="${remote_versions[$i]}"
|
||||
new_version_available+=("$i/$new_version")
|
||||
fi
|
||||
|
||||
echo "${url}"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if [[ -d ${TMP_GNUPGHOME-} ]]; then
|
||||
rm -r "${TMP_GNUPGHOME}"
|
||||
fi
|
||||
|
||||
if [[ -f ${JSON_HEAP-} ]]; then
|
||||
rm "${JSON_HEAP}"
|
||||
fi
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
# Get channel versions from versions.json
|
||||
declare -A versions
|
||||
while IFS='=' read -r key value; do
|
||||
versions["${key}"]="${value}"
|
||||
done < <(jq -r 'to_entries[] | "\(.key)=\(.value)"' versions.json)
|
||||
|
||||
TMP_GNUPGHOME=$(mktemp -dt 1password-gui.gnupghome.XXXXXX)
|
||||
export GNUPGHOME="${TMP_GNUPGHOME}"
|
||||
gpg --no-default-keyring --keyring trustedkeys.kbx \
|
||||
--keyserver keyserver.ubuntu.com \
|
||||
--receive-keys 3FEF9748469ADBE15DA7CA80AC2D62742012EA22
|
||||
|
||||
JSON_HEAP=$(mktemp -t 1password-gui.jsonheap.XXXXXX)
|
||||
for channel in stable beta; do
|
||||
for os in linux darwin; do
|
||||
for arch in x86_64 aarch64; do
|
||||
version="${versions[${channel}-${os}]}"
|
||||
url=$(mk_url ${os} ${channel} ${arch} ${version})
|
||||
nix store prefetch-file --json "${url}" | jq "
|
||||
{
|
||||
\"${channel}\": {
|
||||
\"${arch}-${os}\": {
|
||||
\"url\": \"${url}\",
|
||||
\"hash\": .hash,
|
||||
\"storePath\": .storePath
|
||||
}
|
||||
}
|
||||
}" >> "${JSON_HEAP}"
|
||||
|
||||
# For some reason 1Password PGP signs only Linux binaries.
|
||||
if [[ ${os} == "linux" ]]; then
|
||||
gpgv \
|
||||
$(nix store prefetch-file --json "${url}.sig" | jq -r .storePath) \
|
||||
$(jq -r --slurp ".[-1].[].[].storePath" "${JSON_HEAP}")
|
||||
fi
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
# Combine heap of hash+url objects into a single JSON object.
|
||||
jq --slurp 'reduce .[] as $x ({}; . * $x) | del (.[].[].storePath)' "${JSON_HEAP}" > sources.json
|
||||
if [[ ${#new_version_available[@]} -eq 0 ]]; then
|
||||
# up to date
|
||||
exit
|
||||
fi
|
||||
|
||||
./update-sources.py "${new_version_available[@]}"
|
||||
cat <<EOF
|
||||
[
|
||||
{
|
||||
"attrPath": "${attr_path}",
|
||||
"oldVersion": "${old_version}",
|
||||
"newVersion": "${new_version}",
|
||||
"files": [
|
||||
"$PWD/sources.json"
|
||||
]
|
||||
}
|
||||
]
|
||||
EOF
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"stable-linux": "8.10.78",
|
||||
"stable-darwin": "8.10.78",
|
||||
"beta-linux":"8.10.80-18.BETA",
|
||||
"beta-darwin": "8.10.80-18.BETA"
|
||||
}
|
||||
Reference in New Issue
Block a user