Skip to content

Commit

Permalink
Merge pull request #49 from den4uk/dev
Browse files Browse the repository at this point in the history
Update 3.6
  • Loading branch information
den4uk authored Oct 30, 2021
2 parents be94bc5 + 3c59021 commit 9b5345e
Show file tree
Hide file tree
Showing 23 changed files with 1,666 additions and 1,559 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/python-package-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Python Unit Tests

on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master ]
workflow_dispatch:

jobs:
tests:
name: "Python ${{ matrix.python-version }}"
runs-on: ubuntu-latest
env:
NOTHREAD: true

strategy:
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9"]

steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: "${{ matrix.python-version }}"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Lint with flake8
run: |
flake8 andriller/
- name: Test with pytest
run: |
pytest --cov=andriller tests/
coverage html
29 changes: 29 additions & 0 deletions .github/workflows/python-package-upload.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Test Upload Python Package

on:
release:
types: [published]

jobs:
deploy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
pip install build
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
25 changes: 0 additions & 25 deletions .travis.yml

This file was deleted.

9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
CHANGELOG
===

### 3.6.0 (2021-10-30)

- GUI restructured
- Bugfix with WA decoder
- Dependencies updated
- CI/CD pipelines changed to Github Actions
- Minor FB decoding bugfix when no stickers column is present


### 3.5.3 (2020-11-17)

- Bugfix related to file size retrieval from the remote device.
Expand Down
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Andriller CE (Community Edition)
=====
[![Build Status](https://travis-ci.org/den4uk/andriller.svg?branch=master)](https://travis-ci.org/den4uk/andriller)
![Build Workflow](https://github.com/den4uk/andriller/actions/workflows/python-package-test.yml/badge.svg)
[![License](https://img.shields.io/github/license/den4uk/andriller.svg)](https://pypi.python.org/pypi/andriller)
[![PyPI Version](http://img.shields.io/pypi/v/andriller.svg)](https://pypi.python.org/pypi/andriller)
[![Twitter Follow](https://img.shields.io/twitter/follow/den4uk?style=social)](https://twitter.com/den4uk)
Expand All @@ -21,7 +21,7 @@ Andriller - is software utility with a collection of forensic tools for smartpho


## Python Requirements
- 3.6+ (64-bit version recommended)
- 3.6-3.9 (64-bit version recommended)

> It is highly advised to setup a virtual environment to install Andriller and its dependencies in it. However, it is not essential, and the global environment can also be used. Depending on how Python was setup, it may be needed to substitute `python` and `pip` to `python3` and `pip3` retrospectively for the instructions below.
Expand All @@ -34,12 +34,12 @@ Andriller - is software utility with a collection of forensic tools for smartpho

[Ubuntu/Debian] Install from Terminal:
```bash
$ sudo apt-get install android-tools-adb python3-tk
sudo apt-get install android-tools-adb python3-tk
```

[Mac] Install from brew cask:
```bash
$ brew cask install android-platform-tools
brew cask install android-platform-tools
```

[Windows] : _Included._
Expand All @@ -48,28 +48,28 @@ $ brew cask install android-platform-tools
## Installation (Recommended way)
Create a virtual environment using Python 3:
```bash
$ python3 -m venv env
python3 -m venv env
```

Activate the virtual environment (Linux/Mac):
```bash
$ source env/bin/activate
source env/bin/activate
```

Activate the virtual environment (Windows):
```ps1
> .\env\Scripts\activate
.\env\Scripts\activate
```

Install Andriller with its Python dependencies (same command to upgrade it):
```bash
(env) $ pip install andriller -U
pip install andriller -U
```


## Quick Start (run GUI)
```bash
(env) $ python -m andriller
python -m andriller
```


Expand All @@ -88,4 +88,4 @@ Bugs and issues can be submitted in the ([Issues](https://github.com/den4uk/andr
## Donations
You may make donations to the projects, or you can also just _buy me a beer_:

[![Donate](https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=\_s-xclick&hosted\_button\_id=8AHFL65LMTLLE&source=url)
[![Donate](https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/donate?hosted_button_id=87EX8N3N3SS6C)
5 changes: 3 additions & 2 deletions andriller/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
__version__ = '3.5.3'
__version__ = '3.6.0'
__app_name__ = 'Andriller CE'
__package_name__ = 'andriller'
__website__ = "https://github.com/den4uk/andriller"
__license__ = 'MIT'
__all__ = ['gui']

import os
import logging
Expand Down Expand Up @@ -37,7 +38,7 @@ def run():
os.environ['NOTHREAD'] = '1'

# Run main App
from . import windows
from .gui import windows
try:
root = windows.MainWindow(log_level=level)
root.mainloop()
Expand Down
5 changes: 3 additions & 2 deletions andriller/decoders.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,9 @@ def process_stickers(self):
self.stickers[k] = v

def get_sticker(self, item):
sticker = item['sticker_id']
return self.stickers.get(sticker)
sticker = item.get('sticker_id')
if sticker:
return self.stickers.get(sticker)

def get_recipients(self, item):
return [
Expand Down
2 changes: 1 addition & 1 deletion andriller/driller.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ def DataDecoding(self):
self.update('Decoding extracted data...')
self.logger.debug(self.DOWNLOADS)
workbook = self.get_master_workbook()
for file_name in filter(None.__ne__, self.DOWNLOADS):
for file_name in filter(None, self.DOWNLOADS):
if self.registry.has_target(file_name):
for deco_class in self.registry.decoders_target(file_name):
file_path = os.path.join(self.output_dir, file_name)
Expand Down
2 changes: 2 additions & 0 deletions andriller/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class FileHandlerError(Exception):
pass
Empty file added andriller/gui/__init__.py
Empty file.
167 changes: 167 additions & 0 deletions andriller/gui/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import sys
import os.path
import logging
import functools
import contextlib
import tkinter as tk
from tkinter import ttk, font, filedialog
from .. import __app_name__
from .. import config
from .. import messages
from ..exceptions import FileHandlerError
from ..utils import threaded

logger = logging.getLogger(__name__)


@contextlib.contextmanager
def disable_control(event, *args, **kwargs):
try:
event.widget.config(state=tk.DISABLED)
yield
finally:
event.widget.config(state=tk.NORMAL)


def log_errors(method):
@functools.wraps(method)
def func(self, *args, **kwargs):
try:
return method(self, *args, **kwargs)
except Exception as e:
self.logger.exception(f'{e}')
return func


class BaseWindow:
def __init__(self, root=None, title=__app_name__, **kwargs):
self.log_level = kwargs.get('log_level', logging.INFO)
self.logger = kwargs.get('logger', logger)
self.logger.setLevel(self.log_level)
if root:
self.root = tk.Toplevel(root, takefocus=True)
self.root.protocol("WM_TAKE_FOCUS")
self.root.transient(root)
self.root.bind('<Escape>', lambda e: self.root.destroy)
else:
self.root = tk.Tk()
self.root.bind('<Double-Escape>', self.quit_app)
self.root.protocol("WM_DELETE_WINDOW", self.quit_app)
self.root.title(title)
self.root.resizable(False, False)
self.set_icon()
self.root.grid_columnconfigure(0, weight=1)
self.root.grid_rowconfigure(0, weight=1)
self.NWES = (tk.N, tk.W, tk.E, tk.S)
self.WE = (tk.W, tk.E)
logo_ = os.path.join(config.CODEPATH, 'res', 'logo.gif')
self.img_logo = tk.PhotoImage(master=root, file=logo_)
self.style_ttk = ttk.Style()
self.conf = config.Config()
if self.conf('theme'):
self.style_ttk.theme_use(self.conf('theme'))

self.FontMono = self.get_monospace_font()
self.FontStatus = font.Font(size='10', weight='bold')
self.FontTitle = font.Font(size='12', weight='bold')
self.FontInfo = font.Font(size='9', slant='italic')

self.OUTPUT = tk.StringVar()

self.mainframe = ttk.Frame(self.root, padding=5, relief='groove')
self.mainframe.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
# self.mainframe.grid(row=0, column=0, sticky=self.NWES)
# self.mainframe.columnconfigure(1, weight=1)
# self.mainframe.rowconfigure(0, weight=1)

upframe = ttk.Frame(self.mainframe, padding="5 5 5 5")
upframe.grid(row=0, column=0, columnspan=3, sticky=self.NWES)
ttk.Label(upframe, image=self.img_logo).pack(expand=False, side=tk.TOP)

def set_icon(self):
if 'win32' in sys.platform:
icon_ = os.path.join(config.CODEPATH, 'res', 'icon3.ico')
self.root.iconbitmap(default=icon_)
elif 'linux' in sys.platform:
img_ = tk.Image('photo', file=os.path.join(config.CODEPATH, 'res', 'icon3.png'))
self.root.tk.call('wm', 'iconphoto', self.root._w, img_)

def mainloop(self):
if isinstance(self.root, tk.Tk):
self.root.mainloop()
else:
self.root.wait_window()

def quit_app(self, event=None):
self.root.withdraw()
self.root.destroy()
if isinstance(self.root, tk.Tk):
self.root.quit()

@threaded
def set_output(self):
choose_dir = self.get_dir(path='default_path')
if choose_dir and os.path.isdir(choose_dir):
self.OUTPUT.set(os.path.realpath(choose_dir))

def about_msg(self):
messages.about_msg()

@staticmethod
def get_monospace_font():
return {
'linux': font.Font(size=9, family='Monospace'),
'win32': font.Font(size=9, family='Consolas'),
'darwin': font.Font(size=11, family='Menlo')
}.get(sys.platform, font.Font(size=9, family='Monospace'))

def get_file(self, fname, ftype=[], fsize=0, fsizes=[], lpath='last_path'):
filetypes = [("All files", "*")]
options = {'initialfile': fname, 'initialdir': self.conf(lpath)}
if not self.conf.is_mac:
options['filetypes'] = ftype + filetypes
dialog = filedialog.askopenfilename(**options)
if dialog and os.path.isfile(dialog):
size_ = os.path.getsize(dialog)
if fsize and (size_ != fsize):
raise FileHandlerError(f'The file selected is {size_} bytes, but {fsize} is expected.')
if fsizes and (size_ not in fsizes):
raise FileHandlerError('The file selected is of unexpected size.')
path_ = os.path.split(dialog)[0]
self.conf.update_conf(**{'DEFAULT': {lpath: path_}})
dialog = os.path.realpath(dialog)
return dialog

def get_dir(self, path='last_path'):
dialog = filedialog.askdirectory(initialdir=self.conf(path))
if dialog:
dialog = os.path.realpath(dialog)
self.conf.update_conf(**{'DEFAULT': {'last_path': dialog}})
return dialog


# Extra helpers ---------------------------------------------------------------
def rClicker(e):
try:
def rClick_Copy(e, apnd=0):
e.widget.event_generate('<Control-c>')

def rClick_Cut(e):
e.widget.event_generate('<Control-x>')

def rClick_Paste(e):
e.widget.event_generate('<Control-v>')

e.widget.focus()
nclst = [
(' Cut', lambda e=e: rClick_Cut(e)),
(' Copy', lambda e=e: rClick_Copy(e)),
(' Paste', lambda e=e: rClick_Paste(e)),
]
rmenu = tk.Menu(None, tearoff=0, takefocus=0)
for (txt, cmd) in nclst:
rmenu.add_command(label=txt, command=cmd)
rmenu.tk_popup(e.x_root + 40, e.y_root + 10, entry="0")
except tk.TclError as e:
logger.error(f'rClicker error: {e}')
return "break"
Loading

0 comments on commit 9b5345e

Please sign in to comment.