---
- hosts:
    - 127.0.0.1
  become: yes
  vars:
    pwnagotchi:
      hostname: "{{ lookup('env', 'PWN_HOSTNAME') | default('pwnagotchi', true) }}"
      version: "{{ lookup('env', 'PWN_VERSION') | default('master', true) }}"
    system:
      boot_options:
        - "dtoverlay=dwc2"
        - "dtoverlay=spi1-3cs"
        - "dtparam=spi=on"
        - "dtparam=i2c_arm=on"
        - "dtparam=i2c1=on"
      modules:
        - "i2c-dev"
    services:
      enable:
        - dphys-swapfile.service
        - pwnagotchi.service
        - bettercap.service
        - pwngrid-peer.service
        - epd-fuse.service
      disable:
        - apt-daily.timer
        - apt-daily.service
        - apt-daily-upgrade.timer
        - apt-daily-upgrade.service
        - wpa_supplicant.service
        - bluetooth.service
        - triggerhappy.service
        - ifup@wlan0.service
    packages:
      bettercap:
        url: "https://github.com/bettercap/bettercap/releases/download/v2.26.1/bettercap_linux_armhf_v2.26.1.zip"
        ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip"
      pwngrid:
        url: "https://github.com/evilsocket/pwngrid/releases/download/v1.10.1/pwngrid_linux_armhf_v1.10.1.zip"
      apt:
        hold:
          - firmware-atheros
          - firmware-brcm80211
          - firmware-libertas
          - firmware-misc-nonfree
          - firmware-realtek
        remove:
          - rasberrypi-net-mods
          - dhcpcd5
          - triggerhappy
          - wpa_supplicant
          - nfs-common
        install:
          - vim
          - screen
          - golang
          - git
          - build-essential
          - python3-pip
          - python3-mpi4py
          - python3-smbus
          - unzip
          - gawk
          - libopenmpi-dev
          - libatlas-base-dev
          - libjasper-dev
          - libqtgui4
          - libqt4-test
          - libopenjp2-7
          - libtiff5
          - tcpdump
          - lsof
          - libilmbase23
          - libopenexr23
          - libgstreamer1.0-0
          - libavcodec58
          - libavformat58
          - libswscale5
          - libpcap-dev
          - libusb-1.0-0-dev
          - libnetfilter-queue-dev
          - libopenmpi3
          - dphys-swapfile
          - kalipi-kernel
          - kalipi-bootloader
          - kalipi-re4son-firmware
          - kalipi-kernel-headers
          - libraspberrypi0
          - libraspberrypi-dev
          - libraspberrypi-doc
          - libraspberrypi-bin
          - fonts-dejavu
          - fonts-dejavu-core
          - fonts-dejavu-extra
          - python3-pil
          - python3-smbus
          - libfuse-dev
          - bc
          - fonts-freefont-ttf
          - fbi

  tasks:
  - name: change hostname
    hostname:
      name: "{{pwnagotchi.hostname}}"
    when: lookup('file', '/etc/hostname') == "raspberrypi"
    register: hostname

  - name: add hostname to /etc/hosts
    lineinfile:
      dest: /etc/hosts
      regexp: '^127\.0\.1\.1[ \t]+raspberrypi'
      line: "127.0.1.1\t{{pwnagotchi.hostname}}"
      state: present
    when: hostname.changed

  - name: disable sap plugin for bluetooth.service
    lineinfile:
      dest: /lib/systemd/system/bluetooth.service
      regexp: '^ExecStart=/usr/lib/bluetooth/bluetoothd$'
      line: 'ExecStart=/usr/lib/bluetooth/bluetoothd --noplugin=sap'
      state: present

  - name: Add re4son-kernel repo key
    apt_key:
      url: https://re4son-kernel.com/keys/http/archive-key.asc
      state: present

  - name: Add re4son-kernel repository
    apt_repository:
      repo: deb http://http.re4son-kernel.com/re4son/ kali-pi main
      state: present

  - name: add firmware packages to hold
    dpkg_selections:
      name: "{{ item }}"
      selection: hold
    with_items: "{{ packages.apt.hold }}"

  - name: update apt package cache
    apt:
      update_cache: yes

  - name: remove unecessary apt packages
    apt:
      name: "{{ packages.apt.remove }}"
      state: absent
      purge: yes

  - name: upgrade apt distro
    apt:
      upgrade: dist

  - name: install packages
    apt:
      name: "{{ packages.apt.install }}"
      state: present

  - name: configure dphys-swapfile
    file:
      path: /etc/dphys-swapfile
      content: "CONF_SWAPSIZE=1024"

  - name: clone papirus repository
    git:
      repo: https://github.com/repaper/gratis.git
      dest: /usr/local/src/gratis
    register: gratisgit

  - name: build papirus service
    make:
      chdir: /usr/local/src/gratis
      target: rpi
      params:
        EPD_IO: epd_io.h
        PANEL_VERSION: 'V231_G2'
    when: gratisgit.changed

  - name: install papirus service
    make:
      chdir: /usr/local/src/gratis
      target: rpi-install
      params:
        EPD_IO: epd_io.h
        PANEL_VERSION: 'V231_G2'
    when: gratisgit.changed

  - name: configure papirus display size
    lineinfile:
      dest: /etc/default/epd-fuse
      regexp: "#EPD_SIZE=2.0"
      line: "EPD_SIZE=2.0"

  - name: collect python pip package list
    command: "pip3 list"
    register: pip_output

  - name: set python pip package facts
    set_fact:
      pip_packages: >
        {{ pip_packages | default({}) | combine( { item.split()[0]: item.split()[1] } ) }}
    with_items: "{{ pip_output.stdout_lines }}"

  - name: acquire python3 pip target
    command: "python3 -c 'import sys;print(sys.path.pop())'"
    register: pip_target

  - name: clone pwnagotchi repository
    git:
      repo: https://github.com/evilsocket/pwnagotchi.git
      dest: /usr/local/src/pwnagotchi
    register: pwnagotchigit

  - name: fetch pwnagotchi version
    set_fact:
      pwnagotchi_version: "{{ lookup('file', '/usr/local/src/pwnagotchi/pwnagotchi/__init__.py') | replace('\n', ' ') | regex_replace('.*version.*=.*''([0-9]+\\.[0-9]+\\.[0-9]+[A-Za-z0-9]*)''.*', '\\1') }}"

  - name: pwnagotchi version found
    debug:
      msg: "{{ pwnagotchi_version }}"

  - name: build pwnagotchi wheel
    command: "python3 setup.py sdist bdist_wheel"
    args:
      chdir: /usr/local/src/pwnagotchi
    when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi.version)

  - name: install opencv-python
    pip:
      name: "https://www.piwheels.hostedpi.com/simple/opencv-python/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl"
      extra_args: "--no-deps --no-cache-dir --platform=linux_armv6l --only-binary=:all: --target={{ pip_target.stdout }}"
    when: (pip_packages['opencv-python'] is undefined) or (pip_packages['opencv-python'] != '3.4.3.18')

  - name: install tensorflow
    pip:
      name: "https://www.piwheels.hostedpi.com/simple/tensorflow/tensorflow-1.13.1-cp37-none-linux_armv6l.whl"
      extra_args: "--no-deps --no-cache-dir --platform=linux_armv6l --only-binary=:all: --target={{ pip_target.stdout }}"
    when: (pip_packages['tensorflow'] is undefined) or (pip_packages['tensorflow'] != '1.13.1')

  - name: install pwnagotchi wheel and dependencies
    pip:
      name: "{{ lookup('fileglob', '/usr/local/src/pwnagotchi/dist/pwnagotchi*.whl') }}"
      extra_args: "--no-cache-dir"
    when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi.version)

  - name: download and install pwngrid
    unarchive:
      src: "{{ packages.pwngrid.url }}"
      dest: /usr/bin
      remote_src: yes
      mode: 0755

  - name: download and install bettercap
    unarchive:
      src: "{{ packages.bettercap.url }}"
      dest: /usr/bin
      remote_src: yes
      exclude:
        - README.md
        - LICENSE.md
      mode: 0755

  - name: clone bettercap caplets
    git:
      repo: https://github.com/bettercap/caplets.git
      dest: /tmp/caplets
    register: capletsgit

  - name: install bettercap caplets
    make:
      chdir: /tmp/caplets
      target: install
    when: capletsgit.changed

  - name: download and install bettercap ui
    unarchive:
      src: "{{ packages.bettercap.ui }}"
      dest: /usr/local/share/bettercap/
      remote_src: yes
      mode: 0755

  - name: create bootblink script
    copy:
      dest: /usr/bin/bootblink
      mode: 0755
      content: |
        #!/usr/bin/env bash
        for i in $(seq 1 "$1");
        do
        echo 0 >/sys/class/leds/led0/brightness
        sleep 0.3
        echo 1 >/sys/class/leds/led0/brightness
        sleep 0.3
        done
        echo 0 >/sys/class/leds/led0/brightness
        sleep 0.3

  - name: create pwnagotchi-launcher script
    copy:
      dest: /usr/bin/pwnagotchi-launcher
      mode: 0755
      content: |
        #!/usr/bin/env bash
        # blink 10 times to signal ready state
        /usr/bin/bootblink 10 &
        # start a detached screen session with bettercap
        if [[ $(ifconfig | grep usb0 | grep RUNNING) ]] || [[ !$(grep '1' /sys/class/net/eth0/carrier) ]]; then
          # if override file exists, go into auto mode
          if [ -f /root/.pwnagotchi-auto ]; then
            rm /root/.pwnagotchi-auto
            /usr/local/bin/pwnagotchi
          else
            /usr/local/bin/pwnagotchi --manual
          fi
        else
          /usr/local/bin/pwnagotchi
        fi

  - name: create bettercap-launcher script
    copy:
      dest: /usr/bin/bettercap-launcher
      mode: 0755
      content: |
        #!/usr/bin/env bash
        /usr/bin/monstart
        if [[ $(ifconfig | grep usb0 | grep RUNNING) ]] || [[ !$(grep '1' /sys/class/net/eth0/carrier) ]]; then
          # if override file exists, go into auto mode
          if [ -f /root/.pwnagotchi-auto ]; then
            /usr/bin/bettercap -no-colors -caplet pwnagotchi-auto -iface mon0
          else
            /usr/bin/bettercap -no-colors -caplet pwnagotchi-manual -iface mon0
          fi
        else
          /usr/bin/bettercap -no-colors -caplet pwnagotchi-auto -iface mon0
        fi

  - name: create monstart script
    copy:
      dest: /usr/bin/monstart
      mode: 0755
      content: |
        #!/usr/bin/env bash
        iw phy phy0 interface add mon0 type monitor && ifconfig mon0 up

  - name: create monstop script
    copy:
      dest: /usr/bin/monstop
      mode: 0755
      content: |
        #!/usr/bin/env bash
        ifconfig mon0 down && iw dev mon0 del

  - name: create hdmion script
    copy:
      dest: /usr/bin/hdmion
      mode: 0755
      content: |
        #!/usr/bin/env bash
        sudo /opt/vc/bin/tvservice -p

  - name: create hdmioff script
    copy:
      dest: /usr/bin/hdmioff
      mode: 0755
      content: |
        #!/usr/bin/env bash
        sudo /opt/vc/bin/tvservice -o

  - name: add HDMI powersave to rc.local
    blockinfile:
      path: /etc/rc.local
      insertbefore: "exit 0"
      block: |
        if ! /opt/vc/bin/tvservice -s | egrep 'HDMI|DVI'; then
          /opt/vc/bin/tvservice -o
        fi

  - name: create /etc/pwnagotchi folder
    file:
      path: /etc/pwnagotchi
      state: directory

  - name: check if user configuration exists
    stat:
      path: /etc/pwnagotchi/config.yml
    register: user_config

  - name: create /etc/pwnagotchi/config.yml
    copy:
      dest: /etc/pwnagotchi/config.yml
      content: |
        # Add your configuration overrides on this file any configuration changes done to default.yml will be lost!
        # Example:
        #
        # ui:
        #   display:
        #     type: 'inkyphat'
        #     color: 'black'
        #
    when: not user_config.stat.exists

  - name: configure lo interface
    copy:
      dest: /etc/network/interfaces.d/lo-cfg
      content: |
        auto lo
        iface lo inet loopback

  - name: configure wlan interface
    copy:
      dest: /etc/network/interfaces.d/wlan0-cfg
      content: |
        allow-hotplug wlan0
        iface wlan0 inet static

  - name: configure usb interface
    copy:
      dest: /etc/network/interfaces.d/usb0-cfg
      content: |
        allow-hotplug usb0
        iface usb0 inet static
          address 10.0.0.2
          netmask 255.255.255.0
          network 10.0.0.0
          broadcast 10.0.0.255
          gateway 10.0.0.1

  - name: configure eth0 interface (pi2/3/4)
    copy:
      dest: /etc/network/interfaces.d/eth0-cfg
      content: |
        allow-hotplug eth0
        iface eth0 inet dhcp

  - name: enable ssh on boot
    file:
      path: /boot/ssh
      state: touch

  - name: adjust /boot/config.txt
    lineinfile:
      dest: /boot/config.txt
      insertafter: EOF
      line: '{{ item }}'
    with_items: "{{system.boot_options}}"

  - name: adjust /etc/modules
    lineinfile:
      dest: /etc/modules
      insertafter: EOF
      line: '{{ item }}'
    with_items: "{{system.modules}}"

  - name: change root partition
    replace:
      dest: /boot/cmdline.txt
      backup: no
      regexp: "root=PARTUUID=[a-zA-Z0-9\\-]+"
      replace: "root=/dev/mmcblk0p2"

  - name: configure /boot/cmdline.txt
    lineinfile:
      path: /boot/cmdline.txt
      backrefs: True
      state: present
      backup: no
      regexp: '(.*)$'
      line: '\1 modules-load=dwc2,g_ether'

  - name: configure motd
    copy:
      dest: /etc/motd
      content: |
        (◕‿‿◕) {{pwnagotchi.hostname}} (pwnagotchi-{{pwnagotchi.version}})

        Hi! I'm a pwnagotchi, please take good care of me!
        Here are some basic things you need to know to raise me properly!

        If you want to change my configuration, use /etc/pwnagotchi/config.yml

        All the configuration options can be found on /etc/pwnagotchi/default.yml,
        but don't change this file because I will recreate it every time I'm restarted!

        I'm managed by systemd. Here are some basic commands.

        If you want to know what I'm doing, you can check my logs with the command
        journalctl -fu pwnagotchi

        If you want to know if I'm running, you can use
        systemctl status pwnagotchi

        You can restart me using
        systemctl restart pwnagotchi

        But be aware I will go into MANUAL mode when restarted!
        You can put me back into AUTO mode using
        touch /root/.pwnagotchi-auto && systemctl restart pwnagotchi

        You learn more about me at https://pwnagotchi.ai/
    when: hostname.changed

  - name: clean apt cache
    apt:
      autoclean: yes

  - name: remove dependencies that are no longer required
    apt:
      autoremove: yes

  - name: add pwngrid-peer service to systemd
    copy:
      dest: /etc/systemd/system/pwngrid-peer.service
      content: |
        [Unit]
        Description=pwngrid peer service.
        Documentation=https://pwnagotchi.ai
        Wants=network.target

        [Service]
        Type=simple
        PermissionsStartOnly=true
        ExecStart=/usr/bin/pwngrid -keys /etc/pwnagotchi -address 127.0.0.1:8666 -client-token /root/.api-enrollment.json -wait -log /var/log/pwngrid-peer.log -iface mon0
        Restart=always
        RestartSec=30

        [Install]
        WantedBy=multi-user.target
    notify:
      - reload systemd services

  - name: add bettercap service to systemd
    copy:
      dest: /etc/systemd/system/bettercap.service
      content: |
        [Unit]
        Description=bettercap api.rest service.
        Documentation=https://bettercap.org
        Wants=network.target
        After=pwngrid.service

        [Service]
        Type=simple
        PermissionsStartOnly=true
        ExecStart=/usr/bin/bettercap-launcher
        Restart=always
        RestartSec=30

        [Install]
        WantedBy=multi-user.target
    notify:
      - reload systemd services

  - name: add pwnagotchi service to systemd
    copy:
      dest: /etc/systemd/system/pwnagotchi.service
      content: |
        [Unit]
        Description=pwnagotchi Deep Reinforcement Learning instrumenting bettercap for WiFI pwning.
        Documentation=https://pwnagotchi.ai
        Wants=network.target
        After=bettercap.service

        [Service]
        Type=simple
        PermissionsStartOnly=true
        ExecStart=/usr/bin/pwnagotchi-launcher
        Restart=always
        RestartSec=30

        [Install]
        WantedBy=multi-user.target
    notify:
      - reload systemd services

  - name: enable services
    systemd:
      name: "{{ item }}"
      state: started
      enabled: yes
    with_items: "{{ services.enable }}"

  - name: disable unecessary services
    systemd:
      name: "{{ item }}"
      state: stopped
      enabled: no
    with_items: "{{ services.disable }}"

  - name: remove ssh keys
    file:
      state: absent
      path: "{{item}}"
    with_fileglob:
      - "/etc/ssh/ssh_host*_key*"

  handlers:
  - name: reload systemd services
    systemd:
      daemon_reload: yes