diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..2ef78a5e --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,208 @@ +name: Publish + +on: + workflow_dispatch: + inputs: + version: + description: 'Version number' + required: true + +jobs: + + publish: + runs-on: ubuntu-latest + steps: + + - name: Remove unnecessary directories + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /opt/ghc + sudo rm -rf /usr/local/share/boost + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + + - name: Check disk space + run: df -BG + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Validate tag + id: tag-setter + run: | + TAG=${{ github.event.inputs.version }} + if [[ $TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Tag $TAG is valid." + echo "TAG=$TAG" >> $GITHUB_OUTPUT + else + echo "Tag $TAG is not a valid semantic version. Aborting." + exit 1 + fi + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + sudo apt-get update && sudo apt-get install -y libdbus-1-dev curl unzip gettext qemu-utils qemu qemu-user-static binfmt-support + pip install -r requirements.txt + + - name: Update QEMU + run: | + sudo update-binfmts --enable qemu-aarch64 + echo $(ls /usr/bin/qemu-aarch64-static) + + - name: Restart binfmt-support + run: sudo service binfmt-support restart + + - name: Mount binfmt_misc + run: | + if ! grep -qs '/proc/sys/fs/binfmt_misc ' /proc/mounts; then + echo "Mounting binfmt_misc" + sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc + fi + + - name: Restart binfmt-support + run: sudo service binfmt-support restart + + - name: Update Languages + run: make update_langs + + - name: Compile Languages + run: make compile_langs + + - name: Check disk space + run: df -BG + + - name: Check qemu-user-static package + run: | + echo "Checking qemu-user-static package..." + dpkg -s qemu-user-static && echo "qemu-user-static is installed." || echo "qemu-user-static is NOT installed." + + - name: Check binfmt-support service + run: | + echo "Checking binfmt-support service..." + service binfmt-support status && echo "binfmt-support service is running." || echo "binfmt-support service is NOT running." + + - name: Check binfmt_misc filesystem + run: | + echo "Checking binfmt_misc filesystem..." + mount | grep binfmt_misc && echo "binfmt_misc is mounted." || echo "binfmt_misc is NOT mounted." + echo $(ls /proc/sys/fs/binfmt_misc | grep qemu-aarch64) + + - name: Run Makefile + run: make + env: + PWN_VERSION: ${{ steps.tag-setter.outputs.TAG }} + # - name: Create .img file + # run: | + # dd if=/dev/zero of=/home/runner/work/pwnagotchi-bookworm/pwnagotchi-bookworm/disk.img bs=1M count=1024 + + - name: Compress .img files + run: | + find /home/runner/work/ -type f -name "*.img" -exec xz --no-warn {} \; + + - name: Create tag + uses: actions/github-script@v7 + with: + script: | + const version = "${{ steps.tag-setter.outputs.TAG }}" + console.log(`Creating tag ${version}`) + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `refs/tags/${version}`, + sha: context.sha + }) + + - name: Create Release + id: create_release + uses: actions/github-script@v7 + with: + script: | + const tag = "${{ steps.tag-setter.outputs.TAG }}" + console.log(`Creating release with tag: ${tag}`) + const release = await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: tag, + name: tag, + draft: false, + prerelease: true, + generate_release_notes: true + }) + console.log(`Created release with id: ${release.data.id}`) + return release.data.id + + - name: Upload Release Asset + id: upload-release-asset + uses: actions/github-script@v7 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + script: | + const fs = require('fs'); + const path = require('path'); + const release_id = "${{ steps.create_release.outputs.result }}"; + const asset_content_type = 'application/octet-stream'; + const distDir = '/home/runner/work/'; + + const uploadFile = async (filePath) => { + if (fs.lstatSync(filePath).isDirectory()) { + const files = fs.readdirSync(filePath); + for (const file of files) { + await uploadFile(path.join(filePath, file)); + } + } else { + // Check if the file has a .xz extension + if (path.extname(filePath) === '.xz') { + console.log(`Uploading ${filePath}...`); + + const asset_name = path.basename(filePath); + const asset_size = fs.statSync(filePath).size; + const asset = fs.createReadStream(filePath); + + const response = await github.rest.repos.uploadReleaseAsset({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release_id, + name: asset_name, + data: asset, + headers: { + 'content-type': asset_content_type, + 'content-length': asset_size + } + }); + + console.log(`Uploaded ${filePath}: ${response.data.browser_download_url}`); + } + } + } + + await uploadFile(distDir); + + - name: Update Release + uses: actions/github-script@v7 + with: + script: | + const release_id = "${{ steps.create_release.outputs.result }}" + console.log(`Updating release with id: ${release_id}`) + github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release_id, + tag_name: "${{ steps.tag-setter.outputs.TAG }}", + name: "${{ steps.tag-setter.outputs.TAG }}", + draft: false, + prerelease: false + }) + + - name: Save environment variable + run: echo "${{ steps.tag-setter.outputs.TAG }}" > env_var.txt + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: env-var + path: env_var.txt \ No newline at end of file diff --git a/Makefile b/Makefile index 3f10ad8d..42783236 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ PACKER_VERSION := 1.10.0 PWN_HOSTNAME := pwnagotchi -PWN_VERSION := $(shell cut -d"'" -f2 < pwnagotchi/_version.py) +PWN_VERSION := ${PWN_VERSION} MACHINE_TYPE := $(shell uname -m) ifneq (,$(filter x86_64,$(MACHINE_TYPE))) @@ -64,5 +64,5 @@ pwnagotchi: $(SDIST) builder/pwnagotchi.json.pkr.hcl builder/raspberrypi64.yml $ image: pwnagotchi clean: - - rm -rf build dist pwnagotchi.egg-info + - rm -rf dist pwnagotchi.egg-info - rm -f $(PACKER) diff --git a/builder/data/etc/update-motd.d/01-motd b/builder/data/etc/update-motd.d/01-motd index 08936d4d..31f6c6bd 100755 --- a/builder/data/etc/update-motd.d/01-motd +++ b/builder/data/etc/update-motd.d/01-motd @@ -30,4 +30,4 @@ echo echo " You can restart me using" echo " pwnkill" echo -echo " You learn more about me at https://pwnagotchi.ai/" +echo " You can learn more about me at https://pwnagotchi.org/" diff --git a/builder/pwnagotchi.json.pkr.hcl b/builder/pwnagotchi.json.pkr.hcl index c08ff651..dfc1ba8e 100644 --- a/builder/pwnagotchi.json.pkr.hcl +++ b/builder/pwnagotchi.json.pkr.hcl @@ -2,10 +2,10 @@ # https://github.com/mkaczanowski/packer-builder-arm/pull/172 packer { required_plugins { - #arm = { - # version = "~> 1" - # source = "github.com/cdecoux/builder-arm" - #} + arm = { + version = "1.0.0" + source = "github.com/cdecoux/builder-arm" + } ansible = { source = "github.com/hashicorp/ansible" version = "~> 1" @@ -28,8 +28,8 @@ source "arm" "rpi64-pwnagotchi" { file_target_extension = "xz" file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"] image_path = "../../../pwnagotchi-rpi-bookworm-${var.pwn_version}-arm64.img" - qemu_binary_source_path = "/usr/bin/qemu-aarch64-static" - qemu_binary_destination_path = "/usr/bin/qemu-aarch64-static" + qemu_binary_source_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P" + qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P" image_build_method = "resize" image_size = "9G" image_type = "dos" @@ -51,6 +51,8 @@ source "arm" "rpi64-pwnagotchi" { } } + + # a build block invokes sources and runs provisioning steps on them. The # documentation for build blocks can be found here: # https://www.packer.io/docs/from-1.5/blocks/build @@ -74,10 +76,6 @@ build { inline = ["chmod +x /usr/bin/*"] } - provisioner "shell" { - inline = ["dpkg --add-architecture armhf"] - } - provisioner "file" { destination = "/etc/systemd/system/" sources = [ @@ -86,7 +84,6 @@ build { "data/etc/systemd/system/pwngrid-peer.service", ] } - provisioner "file" { destination = "/etc/update-motd.d/01-motd" source = "data/etc/update-motd.d/01-motd" @@ -95,11 +92,7 @@ build { inline = ["chmod +x /etc/update-motd.d/*"] } provisioner "shell" { - inline = [ - "apt-get -y --allow-releaseinfo-change update", - "apt-get -y dist-upgrade", - "apt-get install -y --no-install-recommends ansible" - ] + inline = ["apt-get -y --allow-releaseinfo-change update", "apt-get -y dist-upgrade", "apt-get install -y --no-install-recommends ansible"] } provisioner "ansible-local" { command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook" diff --git a/builder/raspberrypi64.yml b/builder/raspberrypi64.yml index ec2115b6..985aacd3 100644 --- a/builder/raspberrypi64.yml +++ b/builder/raspberrypi64.yml @@ -44,7 +44,7 @@ ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip" pwngrid: source: "https://github.com/jayofelony/pwngrid.git" - url: "https://github.com/jayofelony/pwngrid/releases/download/v1.10.5/pwngrid-1.10.5-aarch64.zip" + url: "https://github.com/jayofelony/pwngrid/releases/download/v1.10.5/pwngrid-1.11.1-aarch64.zip" apt: downgrade: - libpcap-dev_1.9.1-4_arm64.deb diff --git a/pwnagotchi/ui/hw/waveshare3in52.py b/pwnagotchi/ui/hw/waveshare3in52.py index b2252a0b..3489728a 100644 --- a/pwnagotchi/ui/hw/waveshare3in52.py +++ b/pwnagotchi/ui/hw/waveshare3in52.py @@ -9,36 +9,39 @@ class Waveshare3in52(DisplayImpl): super(Waveshare3in52, self).__init__(config, 'waveshare3in52') def layout(self): - fonts.setup(10, 8, 10, 18, 25, 9) - self._layout['width'] = 240 - self._layout['height'] = 360 - self._layout['face'] = (0, 43) - self._layout['name'] = (0, 14) - self._layout['channel'] = (0, 0) - self._layout['aps'] = (0, 71) - self._layout['uptime'] = (0, 25) - self._layout['line1'] = [0, 12, 240, 12] - self._layout['line2'] = [0, 116, 240, 116] - self._layout['friend_face'] = (12, 88) - self._layout['friend_name'] = (1, 103) - self._layout['shakes'] = (26, 117) - self._layout['mode'] = (0, 117) + fonts.setup(16, 14, 16, 100, 31, 15) + self._layout['width'] = 360 + self._layout['height'] = 240 + self._layout['face'] = (0, 40) + self._layout['name'] = (0, 0) + self._layout['channel'] = (300, 0) + self._layout['aps'] = (0, 220) + self._layout['uptime'] = (120, 0) + self._layout['line1'] = [0, 24, 360, 24] + self._layout['line2'] = [0, 220, 360, 220] + self._layout['friend_face'] = (0, 195) + self._layout['friend_name'] = (0, 185) + self._layout['shakes'] = (100, 220) + self._layout['mode'] = (0,200) self._layout['status'] = { - 'pos': (65, 26), + 'pos': (3, 170), 'font': fonts.status_font(fonts.Small), - 'max': 12 + 'max': 100 } return self._layout def initialize(self): - logging.info("initializing waveshare 3.52 inch lcd display") + logging.info("initializing waveshare 3.52 inch display") from pwnagotchi.ui.hw.libs.waveshare.v3in52.epd3in52 import EPD self._display = EPD() self._display.init() self._display.Clear() def render(self, canvas): - self._display.display(canvas) + buf = self._display.getbuffer(canvas) + self._display.display(buf) + self._display.refresh() + def clear(self): self._display.Clear()