mirror of
https://git.unlock-music.dev/um/cli.git
synced 2025-12-06 12:37:21 +00:00
Compare commits
No commits in common. "791f9c06210ea3c7eb95b616e7d2af3d1581c43b" and "61fba401c7ba83e6a0e69a528460f08b9f0f707c" have entirely different histories.
791f9c0621
...
61fba401c7
148
.drone.jsonnet
Normal file
148
.drone.jsonnet
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// generate .drone.yaml, run:
|
||||||
|
// drone jsonnet --format --stream
|
||||||
|
|
||||||
|
|
||||||
|
local CreateRelease() = {
|
||||||
|
name: 'create release',
|
||||||
|
image: 'plugins/gitea-release',
|
||||||
|
settings: {
|
||||||
|
api_key: { from_secret: 'GITEA_API_KEY' },
|
||||||
|
base_url: 'https://git.unlock-music.dev',
|
||||||
|
files: [
|
||||||
|
'um-*.tar.gz',
|
||||||
|
'um-*.zip',
|
||||||
|
],
|
||||||
|
checksum: 'sha256',
|
||||||
|
draft: true,
|
||||||
|
title: '${DRONE_TAG}',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
local StepGoBuild(GOOS, GOARCH) = {
|
||||||
|
local windows = GOOS == 'windows',
|
||||||
|
local archiveExt = if windows then 'zip' else 'tar.gz',
|
||||||
|
local filepath = 'dist/um-%s-%s-%s.%s' % [GOOS, GOARCH, '$(git describe --tags --always)', archiveExt],
|
||||||
|
|
||||||
|
local archive = if windows then [
|
||||||
|
// Ensure zip is installed
|
||||||
|
'command -v zip >/dev/null || (apt update && apt install -y zip)',
|
||||||
|
'zip -9 -j -r "%s" $DIST_DIR' % filepath,
|
||||||
|
] else [
|
||||||
|
'tar -c -C $DIST_DIR um | gzip -9 > "%s"' % filepath,
|
||||||
|
],
|
||||||
|
|
||||||
|
name: 'go build %s/%s' % [GOOS, GOARCH],
|
||||||
|
image: 'golang:1.23',
|
||||||
|
environment: {
|
||||||
|
GOOS: GOOS,
|
||||||
|
GOARCH: GOARCH,
|
||||||
|
GOPROXY: 'https://goproxy.io,direct',
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
'DIST_DIR=$(mktemp -d)',
|
||||||
|
'go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags --always)" -o $DIST_DIR ./cmd/um',
|
||||||
|
'mkdir -p dist',
|
||||||
|
] + archive,
|
||||||
|
};
|
||||||
|
|
||||||
|
local StepUploadArtifact(GOOS, GOARCH) = {
|
||||||
|
local windows = GOOS == 'windows',
|
||||||
|
local archiveExt = if windows then 'zip' else 'tar.gz',
|
||||||
|
local filename = 'um-%s-%s-%s.%s' % [GOOS, GOARCH, '$(git describe --tags --always)', archiveExt],
|
||||||
|
local filepath = 'dist/%s' % filename,
|
||||||
|
local pkgname = '${DRONE_REPO_NAME}-build',
|
||||||
|
|
||||||
|
name: 'upload artifact',
|
||||||
|
image: 'golang:1.23', // reuse golang:1.19 for curl
|
||||||
|
environment: {
|
||||||
|
DRONE_GITEA_SERVER: 'https://git.unlock-music.dev',
|
||||||
|
GITEA_API_KEY: { from_secret: 'GITEA_API_KEY' },
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
'curl --fail --include --user "um-release-bot:$GITEA_API_KEY" ' +
|
||||||
|
'--upload-file "%s" ' % filepath +
|
||||||
|
'"$DRONE_GITEA_SERVER/api/packages/${DRONE_REPO_NAMESPACE}/generic/%s/${DRONE_BUILD_NUMBER}/%s"' % [pkgname, filename],
|
||||||
|
'sha256sum %s' % filepath,
|
||||||
|
'echo $DRONE_GITEA_SERVER/${DRONE_REPO_NAMESPACE}/-/packages/generic/%s/${DRONE_BUILD_NUMBER}' % pkgname,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
local PipelineBuild(GOOS, GOARCH, RUN_TEST) = {
|
||||||
|
name: 'build %s/%s' % [GOOS, GOARCH],
|
||||||
|
kind: 'pipeline',
|
||||||
|
type: 'docker',
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
name: 'fetch tags',
|
||||||
|
image: 'alpine/git',
|
||||||
|
commands: ['git fetch --tags'],
|
||||||
|
},
|
||||||
|
] +
|
||||||
|
(
|
||||||
|
if RUN_TEST then [{
|
||||||
|
name: 'go test',
|
||||||
|
image: 'golang:1.23',
|
||||||
|
environment: {
|
||||||
|
GOPROXY: 'https://goproxy.io,direct',
|
||||||
|
},
|
||||||
|
commands: ['go test -v ./...'],
|
||||||
|
}] else []
|
||||||
|
)
|
||||||
|
+
|
||||||
|
[
|
||||||
|
StepGoBuild(GOOS, GOARCH),
|
||||||
|
StepUploadArtifact(GOOS, GOARCH),
|
||||||
|
],
|
||||||
|
trigger: {
|
||||||
|
event: ['push', 'pull_request'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
local PipelineRelease() = {
|
||||||
|
name: 'release',
|
||||||
|
kind: 'pipeline',
|
||||||
|
type: 'docker',
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
name: 'fetch tags',
|
||||||
|
image: 'alpine/git',
|
||||||
|
commands: ['git fetch --tags'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'go test',
|
||||||
|
image: 'golang:1.23',
|
||||||
|
environment: {
|
||||||
|
GOPROXY: 'https://goproxy.io,direct',
|
||||||
|
},
|
||||||
|
commands: ['go test -v ./...'],
|
||||||
|
},
|
||||||
|
StepGoBuild('linux', 'amd64'),
|
||||||
|
StepGoBuild('linux', 'arm64'),
|
||||||
|
StepGoBuild('linux', '386'),
|
||||||
|
StepGoBuild('windows', 'amd64'),
|
||||||
|
StepGoBuild('windows', 'arm64'),
|
||||||
|
StepGoBuild('windows', '386'),
|
||||||
|
StepGoBuild('darwin', 'amd64'),
|
||||||
|
StepGoBuild('darwin', 'arm64'),
|
||||||
|
{
|
||||||
|
name: 'prepare root',
|
||||||
|
image: 'golang:1.23',
|
||||||
|
commands: [
|
||||||
|
'mv dist/*.tar.gz dist/*.zip ./',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
CreateRelease(),
|
||||||
|
],
|
||||||
|
trigger: {
|
||||||
|
event: ['tag'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
[
|
||||||
|
PipelineBuild('linux', 'amd64', true),
|
||||||
|
PipelineBuild('windows', 'amd64', false),
|
||||||
|
PipelineBuild('darwin', 'amd64', false),
|
||||||
|
PipelineRelease(),
|
||||||
|
]
|
||||||
257
.drone.yml
Normal file
257
.drone.yml
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: build linux/amd64
|
||||||
|
steps:
|
||||||
|
- commands:
|
||||||
|
- git fetch --tags
|
||||||
|
image: alpine/git
|
||||||
|
name: fetch tags
|
||||||
|
- commands:
|
||||||
|
- go test -v ./...
|
||||||
|
environment:
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go test
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- tar -c -C $DIST_DIR um | gzip -9 > "dist/um-linux-amd64-$(git describe --tags
|
||||||
|
--always).tar.gz"
|
||||||
|
environment:
|
||||||
|
GOARCH: amd64
|
||||||
|
GOOS: linux
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build linux/amd64
|
||||||
|
- commands:
|
||||||
|
- curl --fail --include --user "um-release-bot:$GITEA_API_KEY" --upload-file "dist/um-linux-amd64-$(git
|
||||||
|
describe --tags --always).tar.gz" "$DRONE_GITEA_SERVER/api/packages/${DRONE_REPO_NAMESPACE}/generic/${DRONE_REPO_NAME}-build/${DRONE_BUILD_NUMBER}/um-linux-amd64-$(git
|
||||||
|
describe --tags --always).tar.gz"
|
||||||
|
- sha256sum dist/um-linux-amd64-$(git describe --tags --always).tar.gz
|
||||||
|
- echo $DRONE_GITEA_SERVER/${DRONE_REPO_NAMESPACE}/-/packages/generic/${DRONE_REPO_NAME}-build/${DRONE_BUILD_NUMBER}
|
||||||
|
environment:
|
||||||
|
DRONE_GITEA_SERVER: https://git.unlock-music.dev
|
||||||
|
GITEA_API_KEY:
|
||||||
|
from_secret: GITEA_API_KEY
|
||||||
|
image: golang:1.23
|
||||||
|
name: upload artifact
|
||||||
|
trigger:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
type: docker
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: build windows/amd64
|
||||||
|
steps:
|
||||||
|
- commands:
|
||||||
|
- git fetch --tags
|
||||||
|
image: alpine/git
|
||||||
|
name: fetch tags
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- command -v zip >/dev/null || (apt update && apt install -y zip)
|
||||||
|
- zip -9 -j -r "dist/um-windows-amd64-$(git describe --tags --always).zip" $DIST_DIR
|
||||||
|
environment:
|
||||||
|
GOARCH: amd64
|
||||||
|
GOOS: windows
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build windows/amd64
|
||||||
|
- commands:
|
||||||
|
- curl --fail --include --user "um-release-bot:$GITEA_API_KEY" --upload-file "dist/um-windows-amd64-$(git
|
||||||
|
describe --tags --always).zip" "$DRONE_GITEA_SERVER/api/packages/${DRONE_REPO_NAMESPACE}/generic/${DRONE_REPO_NAME}-build/${DRONE_BUILD_NUMBER}/um-windows-amd64-$(git
|
||||||
|
describe --tags --always).zip"
|
||||||
|
- sha256sum dist/um-windows-amd64-$(git describe --tags --always).zip
|
||||||
|
- echo $DRONE_GITEA_SERVER/${DRONE_REPO_NAMESPACE}/-/packages/generic/${DRONE_REPO_NAME}-build/${DRONE_BUILD_NUMBER}
|
||||||
|
environment:
|
||||||
|
DRONE_GITEA_SERVER: https://git.unlock-music.dev
|
||||||
|
GITEA_API_KEY:
|
||||||
|
from_secret: GITEA_API_KEY
|
||||||
|
image: golang:1.23
|
||||||
|
name: upload artifact
|
||||||
|
trigger:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
type: docker
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: build darwin/amd64
|
||||||
|
steps:
|
||||||
|
- commands:
|
||||||
|
- git fetch --tags
|
||||||
|
image: alpine/git
|
||||||
|
name: fetch tags
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- tar -c -C $DIST_DIR um | gzip -9 > "dist/um-darwin-amd64-$(git describe --tags
|
||||||
|
--always).tar.gz"
|
||||||
|
environment:
|
||||||
|
GOARCH: amd64
|
||||||
|
GOOS: darwin
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build darwin/amd64
|
||||||
|
- commands:
|
||||||
|
- curl --fail --include --user "um-release-bot:$GITEA_API_KEY" --upload-file "dist/um-darwin-amd64-$(git
|
||||||
|
describe --tags --always).tar.gz" "$DRONE_GITEA_SERVER/api/packages/${DRONE_REPO_NAMESPACE}/generic/${DRONE_REPO_NAME}-build/${DRONE_BUILD_NUMBER}/um-darwin-amd64-$(git
|
||||||
|
describe --tags --always).tar.gz"
|
||||||
|
- sha256sum dist/um-darwin-amd64-$(git describe --tags --always).tar.gz
|
||||||
|
- echo $DRONE_GITEA_SERVER/${DRONE_REPO_NAMESPACE}/-/packages/generic/${DRONE_REPO_NAME}-build/${DRONE_BUILD_NUMBER}
|
||||||
|
environment:
|
||||||
|
DRONE_GITEA_SERVER: https://git.unlock-music.dev
|
||||||
|
GITEA_API_KEY:
|
||||||
|
from_secret: GITEA_API_KEY
|
||||||
|
image: golang:1.23
|
||||||
|
name: upload artifact
|
||||||
|
trigger:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
type: docker
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: release
|
||||||
|
steps:
|
||||||
|
- commands:
|
||||||
|
- git fetch --tags
|
||||||
|
image: alpine/git
|
||||||
|
name: fetch tags
|
||||||
|
- commands:
|
||||||
|
- go test -v ./...
|
||||||
|
environment:
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go test
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- tar -c -C $DIST_DIR um | gzip -9 > "dist/um-linux-amd64-$(git describe --tags
|
||||||
|
--always).tar.gz"
|
||||||
|
environment:
|
||||||
|
GOARCH: amd64
|
||||||
|
GOOS: linux
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build linux/amd64
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- tar -c -C $DIST_DIR um | gzip -9 > "dist/um-linux-arm64-$(git describe --tags
|
||||||
|
--always).tar.gz"
|
||||||
|
environment:
|
||||||
|
GOARCH: arm64
|
||||||
|
GOOS: linux
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build linux/arm64
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- tar -c -C $DIST_DIR um | gzip -9 > "dist/um-linux-386-$(git describe --tags --always).tar.gz"
|
||||||
|
environment:
|
||||||
|
GOARCH: "386"
|
||||||
|
GOOS: linux
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build linux/386
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- command -v zip >/dev/null || (apt update && apt install -y zip)
|
||||||
|
- zip -9 -j -r "dist/um-windows-amd64-$(git describe --tags --always).zip" $DIST_DIR
|
||||||
|
environment:
|
||||||
|
GOARCH: amd64
|
||||||
|
GOOS: windows
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build windows/amd64
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- command -v zip >/dev/null || (apt update && apt install -y zip)
|
||||||
|
- zip -9 -j -r "dist/um-windows-arm64-$(git describe --tags --always).zip" $DIST_DIR
|
||||||
|
environment:
|
||||||
|
GOARCH: arm64
|
||||||
|
GOOS: windows
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build windows/arm64
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- command -v zip >/dev/null || (apt update && apt install -y zip)
|
||||||
|
- zip -9 -j -r "dist/um-windows-386-$(git describe --tags --always).zip" $DIST_DIR
|
||||||
|
environment:
|
||||||
|
GOARCH: "386"
|
||||||
|
GOOS: windows
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build windows/386
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- tar -c -C $DIST_DIR um | gzip -9 > "dist/um-darwin-amd64-$(git describe --tags
|
||||||
|
--always).tar.gz"
|
||||||
|
environment:
|
||||||
|
GOARCH: amd64
|
||||||
|
GOOS: darwin
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build darwin/amd64
|
||||||
|
- commands:
|
||||||
|
- DIST_DIR=$(mktemp -d)
|
||||||
|
- go build -v -trimpath -ldflags="-w -s -X main.AppVersion=$(git describe --tags
|
||||||
|
--always)" -o $DIST_DIR ./cmd/um
|
||||||
|
- mkdir -p dist
|
||||||
|
- tar -c -C $DIST_DIR um | gzip -9 > "dist/um-darwin-arm64-$(git describe --tags
|
||||||
|
--always).tar.gz"
|
||||||
|
environment:
|
||||||
|
GOARCH: arm64
|
||||||
|
GOOS: darwin
|
||||||
|
GOPROXY: https://goproxy.io,direct
|
||||||
|
image: golang:1.23
|
||||||
|
name: go build darwin/arm64
|
||||||
|
- commands:
|
||||||
|
- mv dist/*.tar.gz dist/*.zip ./
|
||||||
|
image: golang:1.23
|
||||||
|
name: prepare root
|
||||||
|
- image: plugins/gitea-release
|
||||||
|
name: create release
|
||||||
|
settings:
|
||||||
|
api_key:
|
||||||
|
from_secret: GITEA_API_KEY
|
||||||
|
base_url: https://git.unlock-music.dev
|
||||||
|
checksum: sha256
|
||||||
|
draft: true
|
||||||
|
files:
|
||||||
|
- um-*.tar.gz
|
||||||
|
- um-*.zip
|
||||||
|
title: ${DRONE_TAG}
|
||||||
|
trigger:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
type: docker
|
||||||
@ -73,14 +73,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup vars
|
|
||||||
id: vars
|
|
||||||
run: |
|
|
||||||
echo "::set-output name=git_tag::$(git describe --tags --always)"
|
|
||||||
- name: prepare archive
|
- name: prepare archive
|
||||||
run: |
|
run: |
|
||||||
mkdir -p dist prepare
|
mkdir -p dist prepare
|
||||||
@ -89,11 +81,26 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: prepare
|
path: prepare
|
||||||
pattern: um-*
|
pattern: um-*
|
||||||
- name: repack archive
|
- name: prepare archive
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
for exe in prepare/*/um-*.exe; do
|
||||||
apt-get install -y strip-nondeterminism
|
zip -9 -j "dist/$(basename "$exe" .exe).zip" "$exe"
|
||||||
./misc/repack.sh "${{ steps.vars.outputs.git_tag }}"
|
rm -f "$exe"
|
||||||
|
done
|
||||||
|
for exe in prepare/*/um-*; do
|
||||||
|
tar \
|
||||||
|
--sort=name --format=posix \
|
||||||
|
--pax-option=exthdr.name=%d/PaxHeaders/%f \
|
||||||
|
--pax-option=delete=atime,delete=ctime \
|
||||||
|
--clamp-mtime --mtime='1970-01-01T00:00:00Z' \
|
||||||
|
--numeric-owner --owner=0 --group=0 \
|
||||||
|
--mode=0755 \
|
||||||
|
-cv \
|
||||||
|
-C "$(dirname "$exe")" \
|
||||||
|
"$(basename "$exe")" \
|
||||||
|
| gzip -9 > "dist/$(basename "$exe").tar.gz"
|
||||||
|
rm -f "$exe"
|
||||||
|
done
|
||||||
- name: Publish all-in-one archive
|
- name: Publish all-in-one archive
|
||||||
uses: christopherhx/gitea-upload-artifact@v4
|
uses: christopherhx/gitea-upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@ -28,7 +28,7 @@ var DEFAULT_MASTER_KEY = []byte{
|
|||||||
0x73, 0x41, 0x6C, 0x54, // fixed value
|
0x73, 0x41, 0x6C, 0x54, // fixed value
|
||||||
}
|
}
|
||||||
|
|
||||||
func deriveIvSeed(seed uint32) uint32 {
|
func next_page_iv(seed uint32) uint32 {
|
||||||
var left uint32 = seed * 0x9EF4
|
var left uint32 = seed * 0x9EF4
|
||||||
var right uint32 = seed / 0xce26 * 0x7FFFFF07
|
var right uint32 = seed / 0xce26 * 0x7FFFFF07
|
||||||
var value uint32 = left - right
|
var value uint32 = left - right
|
||||||
@ -38,28 +38,25 @@ func deriveIvSeed(seed uint32) uint32 {
|
|||||||
return value + 0x7FFF_FF07
|
return value + 0x7FFF_FF07
|
||||||
}
|
}
|
||||||
|
|
||||||
// derivePageIv generates a 16-byte IV for database page.
|
func derive_page_aes_key(seed uint32) []byte {
|
||||||
func derivePageIv(page uint32) []byte {
|
master_key := make([]byte, len(DEFAULT_MASTER_KEY))
|
||||||
|
copy(master_key, DEFAULT_MASTER_KEY)
|
||||||
|
binary.LittleEndian.PutUint32(master_key[0x10:0x14], seed)
|
||||||
|
digest := md5.Sum(master_key)
|
||||||
|
return digest[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func derive_page_aes_iv(seed uint32) []byte {
|
||||||
iv := make([]byte, 0x10)
|
iv := make([]byte, 0x10)
|
||||||
page = page + 1
|
seed = seed + 1
|
||||||
for i := 0; i < 0x10; i += 4 {
|
for i := 0; i < 0x10; i += 4 {
|
||||||
page = deriveIvSeed(page)
|
seed = next_page_iv(seed)
|
||||||
binary.LittleEndian.PutUint32(iv[i:i+4], page)
|
binary.LittleEndian.PutUint32(iv[i:i+4], seed)
|
||||||
}
|
}
|
||||||
digest := md5.Sum(iv)
|
digest := md5.Sum(iv)
|
||||||
return digest[:]
|
return digest[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// derivePageKey generates a 16-byte AES key for database page.
|
|
||||||
func derivePageKey(page uint32) []byte {
|
|
||||||
masterKey := make([]byte, len(DEFAULT_MASTER_KEY))
|
|
||||||
copy(masterKey, DEFAULT_MASTER_KEY)
|
|
||||||
binary.LittleEndian.PutUint32(masterKey[0x10:0x14], page)
|
|
||||||
digest := md5.Sum(masterKey)
|
|
||||||
return digest[:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// aes128cbcDecryptNoPadding decrypts the given buffer using AES-128-CBC with no padding.
|
|
||||||
func aes128cbcDecryptNoPadding(buffer, key, iv []byte) error {
|
func aes128cbcDecryptNoPadding(buffer, key, iv []byte) error {
|
||||||
if len(key) != 16 {
|
if len(key) != 16 {
|
||||||
return fmt.Errorf("invalid key size: %d (must be 16 bytes for AES-128)", len(key))
|
return fmt.Errorf("invalid key size: %d (must be 16 bytes for AES-128)", len(key))
|
||||||
@ -81,40 +78,43 @@ func aes128cbcDecryptNoPadding(buffer, key, iv []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// decryptPage decrypts a single database page using AES-128-CBC (no padding).
|
func decrypt_db_page(buffer []byte, page_number uint32) error {
|
||||||
// page start from 1.
|
key := derive_page_aes_key(page_number)
|
||||||
func decryptPage(buffer []byte, page uint32) error {
|
iv := derive_page_aes_iv(page_number)
|
||||||
key := derivePageKey(page)
|
|
||||||
iv := derivePageIv(page)
|
|
||||||
|
|
||||||
return aes128cbcDecryptNoPadding(buffer, key, iv)
|
return aes128cbcDecryptNoPadding(buffer, key, iv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decryptPage1(buffer []byte) error {
|
func decrypt_page_1(page []byte) error {
|
||||||
if err := validateFirstPageHeader(buffer); err != nil {
|
if err := validate_page_1_header(page); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup expected header, swap cipher text
|
// Backup expected hdr value
|
||||||
expectedHeader := make([]byte, 8)
|
|
||||||
copy(expectedHeader, buffer[0x10:0x18])
|
expected_hdr_value := make([]byte, 8)
|
||||||
copy(buffer[0x10:0x18], buffer[0x08:0x10])
|
copy(expected_hdr_value, page[0x10:0x18])
|
||||||
if err := decryptPage(buffer[0x10:], 1); err != nil {
|
|
||||||
|
// Copy encrypted hdr over
|
||||||
|
hdr := page[:0x10]
|
||||||
|
copy(page[0x10:0x18], hdr[0x08:0x10])
|
||||||
|
|
||||||
|
if err := decrypt_db_page(page[0x10:], 1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate header
|
// Validate header
|
||||||
if !bytes.Equal(buffer[0x10:0x18], expectedHeader) {
|
if !bytes.Equal(page[0x10:0x18], expected_hdr_value[:8]) {
|
||||||
return fmt.Errorf("decrypt page 1 failed")
|
return fmt.Errorf("decrypt page 1 failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore SQLite file header
|
// Apply SQLite header
|
||||||
copy(buffer[:0x10], SQLITE_HEADER)
|
copy(hdr, SQLITE_HEADER)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateFirstPageHeader(header []byte) error {
|
func validate_page_1_header(header []byte) error {
|
||||||
o10 := binary.LittleEndian.Uint32(header[0x10:0x14])
|
o10 := binary.LittleEndian.Uint32(header[0x10:0x14])
|
||||||
o14 := binary.LittleEndian.Uint32(header[0x14:0x18])
|
o14 := binary.LittleEndian.Uint32(header[0x14:0x18])
|
||||||
|
|
||||||
@ -126,28 +126,28 @@ func validateFirstPageHeader(header []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decryptDatabase(buffer []byte) error {
|
func decryptPcDatabase(buffer []byte) error {
|
||||||
dbSize := len(buffer)
|
db_size := len(buffer)
|
||||||
|
|
||||||
// not encrypted
|
// not encrypted
|
||||||
if bytes.Equal(buffer[:len(SQLITE_HEADER)], SQLITE_HEADER) {
|
if bytes.Equal(buffer[:len(SQLITE_HEADER)], SQLITE_HEADER) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if dbSize%PAGE_SIZE != 0 || dbSize == 0 {
|
if db_size%PAGE_SIZE != 0 || db_size == 0 {
|
||||||
return fmt.Errorf("invalid database size: %d", dbSize)
|
return fmt.Errorf("invalid database size: %d", db_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := decryptPage1(buffer[:PAGE_SIZE]); err != nil {
|
last_page := db_size / PAGE_SIZE
|
||||||
|
|
||||||
|
// page 1 is the header
|
||||||
|
if err := decrypt_page_1(buffer[:PAGE_SIZE]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
offset := PAGE_SIZE
|
offset := PAGE_SIZE
|
||||||
lastPage := uint32(dbSize / PAGE_SIZE)
|
for page_no := 2; page_no <= last_page; page_no++ {
|
||||||
|
if err := decrypt_db_page(buffer[offset:offset+PAGE_SIZE], uint32(page_no)); err != nil {
|
||||||
var pageNumber uint32
|
|
||||||
for pageNumber = 2; pageNumber <= lastPage; pageNumber++ {
|
|
||||||
if err := decryptPage(buffer[offset:offset+PAGE_SIZE], uint32(pageNumber)); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
offset += PAGE_SIZE
|
offset += PAGE_SIZE
|
||||||
@ -223,7 +223,7 @@ func CachedDumpEKey(dbPath string) (map[string]string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err = decryptDatabase(buffer); err != nil {
|
if err = decryptPcDatabase(buffer); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dump, err = extractKeyMapping(buffer)
|
dump, err = extractKeyMapping(buffer)
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
func TestDerivePageAESKey_Page0(t *testing.T) {
|
func TestDerivePageAESKey_Page0(t *testing.T) {
|
||||||
expectedKey := []byte{0x19, 0x62, 0xc0, 0x5f, 0xa2, 0xeb, 0xbe, 0x24, 0x28, 0xff, 0x52, 0x2b, 0x9e, 0x03, 0xea, 0xd4}
|
expectedKey := []byte{0x19, 0x62, 0xc0, 0x5f, 0xa2, 0xeb, 0xbe, 0x24, 0x28, 0xff, 0x52, 0x2b, 0x9e, 0x03, 0xea, 0xd4}
|
||||||
pageKey := derivePageKey(0)
|
pageKey := derive_page_aes_key(0)
|
||||||
if !reflect.DeepEqual(expectedKey, pageKey) {
|
if !reflect.DeepEqual(expectedKey, pageKey) {
|
||||||
t.Errorf("Derived AES key for page 0 does not match expected value: got %v, want %v", pageKey, expectedKey)
|
t.Errorf("Derived AES key for page 0 does not match expected value: got %v, want %v", pageKey, expectedKey)
|
||||||
}
|
}
|
||||||
@ -15,7 +15,7 @@ func TestDerivePageAESKey_Page0(t *testing.T) {
|
|||||||
|
|
||||||
func TestDerivePageAESIv_Page0(t *testing.T) {
|
func TestDerivePageAESIv_Page0(t *testing.T) {
|
||||||
expectedIv := []byte{0x05, 0x5a, 0x67, 0x35, 0x93, 0x89, 0x2d, 0xdf, 0x3a, 0xb3, 0xb3, 0xc6, 0x21, 0xc3, 0x48, 0x02}
|
expectedIv := []byte{0x05, 0x5a, 0x67, 0x35, 0x93, 0x89, 0x2d, 0xdf, 0x3a, 0xb3, 0xb3, 0xc6, 0x21, 0xc3, 0x48, 0x02}
|
||||||
pageKey := derivePageIv(0)
|
pageKey := derive_page_aes_iv(0)
|
||||||
if !reflect.DeepEqual(expectedIv, pageKey) {
|
if !reflect.DeepEqual(expectedIv, pageKey) {
|
||||||
t.Errorf("Derived AES iv for page 0 does not match expected value: got %v, want %v", pageKey, expectedIv)
|
t.Errorf("Derived AES iv for page 0 does not match expected value: got %v, want %v", pageKey, expectedIv)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
#!/bin/bash -e
|
|
||||||
# see .gitea/workflows/build.yml
|
|
||||||
|
|
||||||
APP_VERSION="${1:-$(git describe --tags --always)}"
|
|
||||||
|
|
||||||
for exe in prepare/*/um-*.exe; do
|
|
||||||
name="$(basename "$exe" .exe)-$APP_VERSION"
|
|
||||||
new_exe="$(dirname "$exe")/um.exe"
|
|
||||||
mv "$exe" "$new_exe"
|
|
||||||
|
|
||||||
echo "archiving ${new_exe}..."
|
|
||||||
zip -Xqj9 "dist/${name}.zip" "$new_exe"
|
|
||||||
rm -f "$new_exe"
|
|
||||||
done
|
|
||||||
|
|
||||||
for exe in prepare/*/um-*; do
|
|
||||||
name="$(basename "$exe")-$APP_VERSION"
|
|
||||||
new_exe="$(dirname "$exe")/um"
|
|
||||||
mv "$exe" "$new_exe"
|
|
||||||
|
|
||||||
echo "archiving ${new_exe}..."
|
|
||||||
tar \
|
|
||||||
--sort=name --format=posix \
|
|
||||||
--pax-option=exthdr.name=%d/PaxHeaders/%f \
|
|
||||||
--pax-option=delete=atime,delete=ctime \
|
|
||||||
--clamp-mtime --mtime='1970-01-01T00:00:00Z' \
|
|
||||||
--numeric-owner --owner=0 --group=0 \
|
|
||||||
--mode=0755 \
|
|
||||||
-c -C "$(dirname "$exe")" um |
|
|
||||||
gzip -9 >"dist/${name}.tar.gz"
|
|
||||||
rm -f "$exe"
|
|
||||||
done
|
|
||||||
|
|
||||||
pushd dist
|
|
||||||
|
|
||||||
if command -v strip-nondeterminism >/dev/null 2>&1; then
|
|
||||||
echo 'strip archives...'
|
|
||||||
strip-nondeterminism *.zip *.tar.gz
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo 'Creating checksum...'
|
|
||||||
sha256sum *.zip *.tar.gz >sha256sum.txt
|
|
||||||
popd
|
|
||||||
Loading…
Reference in New Issue
Block a user