Merge pull request #45 from dputtick/repo-cleanup

Documentation and reorganizing repo
pull/61/head
Raphaël Vinot 2017-01-17 11:12:01 -05:00 committed by GitHub
commit 52ee749a45
42 changed files with 308 additions and 1599 deletions

50
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,50 @@
Building the project
====================
To get started contributing to Circlean, first, fork the project and `git clone`
your fork. Then, follow the instructions in [README_setup.md](README_setup.md)
to build an image.
The issue tracker
=================
If you find a bug or see a problem with PyCIRCLean, please open an issue in the Github
repo. We'll do our best to respond as quickly as possible. Also, feel free to contribute a solution
to any of the open issues - we'll do our best to review your pull request in a timely manner.
This project is in active development, so any contributions are welcome!
Running the tests
=================
To emulate the Raspberry Pi hardware for testing, we'll be using
[Qemu](http://wiki.qemu.org/Main_Page), an open source machine emulator.
The "qemu" package available for Ubuntu/Debian includes all of the required
packages (including qemu-system-arm) except for qemu-user-static, which must
be installed separately.
```
sudo apt-get install qemu qemu-user-static expect
```
* Get the qemu kernel for the image you are using:
```
pushd tests; wget https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu; popd
```
* Put some test data from tests/testFiles into tests/content_img_vfat_norm
* Comment out the other tests in tests/run.sh or populate those directories as
well
* Make sure to set the filename of the image and the kernel in `tests/run.sh`
* Run the tests:
```
sudo ./run_tests.sh
```
* If the image run processed images correctly but doesn't exit and unmount the
images cleanly, look at tests/run.exp and make sure it's waiting for the
string your qemu and kernel actually produce.

View File

@ -6,83 +6,81 @@ CIRCLean
How To
======
[Graphical how-to and pre-build image](http://circl.lu/projects/CIRCLean/).
[Graphical how-to and pre-built image](http://circl.lu/projects/CIRCLean/).
To prepare the SD card on Windows, you can use [Win32DiskImager] (http://sourceforge.net/projects/win32diskimager/).
To prepare the SD card on Windows, you can use [Win32DiskImager](http://sourceforge.net/projects/win32diskimager/).
And the linux way is in the command line, via dd (see in copy_to_final.sh)
If you'd like to contribute to the project or build the image yourself, see
[contributing](CONTRIBUTING.md) and the [setup readme](README_setup.md).
Why/What
========
This project aims to be used in case you got an USB key you do not know what is
contains but still want to have a look.
This project aims to be useful when you get/find a USB key that you can't trust,
and you want to have a look at its contents without taking the risk of plugging it into your
main computer directly.
Work in progress, contributions welcome:
This is a work in progress - contributions are welcome:
The content of the first key will be copyed or/and converted to the second key
following theses rules (based on the mime type):
- direct copy of plain text files (mime type: text/*)
- direct copy of audio files (mime type: audio/*)
- direct copy of image files (mime type: image/*)
- direct copy of video files (mime type: video/*)
- direct copy of example files (mime type: example/*)
- direct copy of message files (mime type: message/*)
- direct copy of model files (mime type: model/*)
- direct copy of multipart files (mime type: multipart/*)
- Copying or converting the application files this way (mime type: application/*):
- pdf => HTML
- msword|vnd.openxmlformats-officedocument.*|vnd.ms-*|vnd.oasis.opendocument* => pdf => html
- *xml* => copy as a text file
- x-dosexec (executable) => prepend and append DANGEROUS to the filename
- x-gzip|x-tar|x-7z-compressed => compressed file
- octet-stream => direct copy
Compressed files (zip|x-rar|x-bzip2|x-lzip|x-lzma|x-lzop|x-xz|x-compress|x-gzip|x-tar|*compressed):
- Unpacking of archives
- Recursively run the rules on the unpacked files
The content of the first key will be copied or/and converted to the second key
following these rules (based on the mime type, as determined by libmagic):
- Direct copy of:
- Plain text files (mime type: text/*)
- Audio files (mime type: audio/*)
- Video files (mime type: video/*)
- Example files (mime type: example/*)
- Multipart files (mime type: multipart/*)
- *xml* files, after being converted to text files
- Octet-stream files
- Copied after verification:
- Image files after verifying that they are not compression bombs (mime type: image/*)
- PDF files, after marking as dangerous if they contain malicious content
- msword|vnd.openxmlformats-officedocument.*|vnd.ms-*|vnd.oasis.opendocument*, after
parsing with oletools/olefile and marking as dangerous if the parsing fails.
- Copied but marked as dangerous (DANGEROUS_filename_DANGEROUS)
- Message files (mime type: message/*)
- Model files (mime type: model/*)
- x-dosexec (executable)
- Compressed files (zip|x-rar|x-bzip2|x-lzip|x-lzma|x-lzop|x-xz|x-compress|x-gzip|x-tar|*compressed):
- Archives are unpacked, with the unpacking process stopped after 2 levels of archives
to prevent archive bombs.
- The above rules are applied recursively to the unpacked files.
Usage
=====
0. Power off the device
1. Plug the untrusted key in the top usb slot of the Raspberry Pi
2. Plug your own key in the bottom usb slot
0. Power off the device and unplug all connections.
1. Plug the untrusted key in the top USB slot of the Raspberry Pi.
2. Plug your own key in the bottom USB slot (or use any of the other slots if
there are more than 2).
*Note*: This key should be bigger than the original one because the archives
will be copyed
*Note*: This key should be bigger than the original one because any archives
present on the source key will be expanded and copied.
3. Optional: connect the HDMI cable to a screen to see what happen
4. Connect the power to the micro USB
3. Optional: connect the HDMI cable to a screen to monitor the process.
4. Connect the power to the micro USB port.
*Note*: 5V, 700mA regulated power supply
*Note*: Use a 5V, 700mA+ regulated power supply
5. Wait until you do not see any blinking green light on the board, or if you
connected the HDMI cable, check the screen
it's slow and can take 30-60 minutes depending on how many document
conversions take place
6. Power off the device and disconnect the drives
connected the HDMI cable, check the screen. The process is slow and can take
30-60 minutes depending on how many document conversions take place.
6. Power off the device and disconnect the drives.
Helper scripts
==============
You should use them as example when you are creating a new image and probably not
run them blindly as you will most probably have to change constraints accordingly to
You should use them as examples when you are creating a new image and probably not
run them blindly as you will most probably have to change parameters accordingly to
your configuration.
IN ALL CASES, PLEASE READ THE COMMENTS IN THE SCRIPTS AT LEAST ONCE.
* proper_chroot.sh: uses qemu to chroot into a raspbian instance (.img or SD Card)
* prepare_rPI_builder.sh: update the system, add the repositories and install all
the dependencies needed to compile poppler and pdf2htmlEX on a rPi
* update_builder.sh: compile the latest version of poppler from debian experimental,
pull and compile the latest version of pdf2htmlEX from the git repository
* prepare_rPI.sh: update the system, install the dependencies of poppler and pdf2htmlEX,
install poppler and pdf2htmlEX (the deb packages compiled in the builder)
* prepare_rPI.sh: update the system, some configuration
* create_user.sh: create the user who will run the scripts, assign the proper sudo rights.
* copy_to_final.sh: populate the content of the directory fs/ in the image,
contains a sample of dd command to write the image on the SD card.
*TAKE CARE NOT USING THE WRONG DESTINATION*
NOTE: TAKE CARE NOT TO USE THE WRONG DESTINATION

View File

@ -1,85 +0,0 @@
Install Qemu and Expect
============
Install the necessary packages:
```
sudo apt-get install qemu qemu-user-static expect
```
Create a new image from scratch
===============================
* Download the most recent version of Raspbian Jessie lite:
https://downloads.raspberrypi.org/raspbian_lite_latest
* Unpack it:
```
unzip 2016-03-18-raspbian-jessie-lite.zip
```
Prepare the image
=================
It will be used for the build environment and the final image.
* [Add empty space to the image](resize_img.md)
* Chroot in the image
```
sudo ./proper_chroot.sh
```
* Change your user to root (your global variables may be broken)
```
su root
```
* The locales may be broken, fix it (remove `en_GB.UTF-8 UTF-8`, set `en_US.UTF-8 UTF-8`):
```
dpkg-reconfigure locales
```
* In the image, make sure everything is up-to-date, and remove the old packages
```
apt-get update
apt-get dist-upgrade
apt-get autoremove
apt-get install timidity git p7zip-full python-dev python-pip python-lxml pmount libjpeg-dev libtiff-dev libwebp-dev liblcms2-dev tcl-dev tk-dev python-tk libxml2-dev libxslt1-dev
```
* Install python requirements
```
pip install oletools olefile exifread Pillow
pip install git+https://github.com/Rafiot/officedissector.git
pip install git+https://github.com/CIRCL/PyCIRCLean.git
```
* Create the user and mtab for a RO filesystem
```
useradd -m kitten
chown -R kitten:kitten /home/kitten
ln -s /proc/mounts /etc/mtab
```
* Copy the files
```
sudo ./copy_to_final.sh /mnt/arm_rPi/
```
* Enable rc.local
```
systemctl enable rc-local.service
```

View File

@ -1,232 +0,0 @@
Install Qemu and Expect
============
Install the necessary packages:
```
sudo apt-get install qemu qemu-user-static expect
```
Create a new image from scratch
===============================
* Download the most recent version of Raspbian Jessie lite:
https://downloads.raspberrypi.org/raspbian_lite_latest
* Unpack it:
```
unzip 2016-03-18-raspbian-jessie-lite.zip
```
Prepare the base image
======================
It will be used for the build environment and the final image.
* [Add empty space to the image](resize_img.md)
* Chroot in the image
```
sudo ./proper_chroot.sh
```
* Change your user to root (your global variables may be broken)
```
su root
```
* The locales may be broken, fix it (remove `en_GB.UTF-8 UTF-8`, set `en_US.UTF-8 UTF-8`):
```
dpkg-reconfigure locales
```
* In the image, make sure everything is up-to-date, and remove the old packages
```
apt-get update
apt-get dist-upgrade
apt-get autoremove
```
Setup two images
================
* Create two separate images: one will be used to build the deb packages that are not available in wheezy
```
mv raspbian-wheezy.img BUILDENV-raspbian-wheezy.img
cp BUILDENV-raspbian-wheezy.img FINAL-raspbian-wheezy.img
```
Build environment specifics
===========================
* Create a symlink to the build image
```
ln -s BUILDENV-raspbian-wheezy.img raspbian-wheezy.img
```
* Chroot in the image
```
sudo ./proper_chroot.sh
```
* Change your user to root (your global variables may be broken)
```
su root
```
* Add Wheezy backports source packages to build a poppler version compatible with pdf2htmlEX
```
echo 'deb-src http://ftp.debian.org/debian/ wheezy-backports main' >> /etc/apt/sources.list
apt-get instal debian-keyring debian-archive-keyring
apt-get update
```
* Get the required build dependencies and the sources
```
apt-get build-dep poppler
apt-get source poppler
```
* Compile the package
```
cd poppler-<VERSION>/
dpkg-buildpackage
```
At least on Debian 8, you may receive an error about libpoppler-glib-dev missing the gir1.2-poppler requirement; you can ignore it.
* Install the packages required by pdf2htmlEX
```
apt-get install cmake libfontforge-dev libspiro-dev python-dev default-jre-headless
cd ..
dpkg -i libpoppler-dev* libpoppler* libpoppler-private-dev*
```
* Download the sources of pdf2htmlEX (we cannot use anything newer than v0.11 because fontforge>=2.0 is not available)
```
wget https://github.com/Rafiot/pdf2htmlEX/archive/KittenGroomer.zip
unzip KittenGroomer.zip
```
* Compile the package
```
cd pdf2htmlEX-KittenGroomer/
dpkg-buildpackage -uc -b
```
* Get the packages out of the building image (run it outside of the chroot)
```
cp /mnt/arm_rPi/libpoppler46_* /mnt/arm_rPi/pdf2htmlex_* deb/
```
Final image specifics
=====================
* Change the link to the image
```
rm raspbian-wheezy.img
ln -s FINAL-raspbian-wheezy.img -raspbian-wheezy.img
```
* Chroot in the image
```
sudo ./proper_chroot.sh
```
* Change your user to root (your global variables may be broken)
```
su root
```
* Copy the debian packages into the chroot (run it outside of the chroot)
```
cp deb/*.deb /mnt/arm_rPi/
```
* Install repencencies required by the project
```
apt-get install libreoffice p7zip-full libfontforge1 timidity freepats pmount ntfs-3g unoconv python-pip
dpkg -i *.deb
pip install twiggy python-magic
```
* Create the user, make Libreoffice and mtab working on a RO filesystem
```
useradd -m kitten
pushd /home/kitten
ln -s /tmp/libreoffice
mkdir .config/
ln -s /tmp/libreoffice_config .config/libreoffice
popd
chown -R kitten:kitten /home/kitten
ln -s /proc/mounts /etc/mtab
```
* Copy the script to the image
```
sudo ./copy_to_final.sh
```
* Get the PyCIRCLean modules
```
pip install git+https://github.com/CIRCL/PyCIRCLean
```
* Exit the chroot
Write the image on a SD card
============================
*WARNING*: Make sure you write on the right filesystem
```
sudo dd bs=4M if=FINAL-raspbian-wheezy.img of=/dev/<FILESYSTEM>
```
Run the tests
=============
* Get the qemu kernel:
```
pushd tests; wget https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu; popd
```
* Put some test data from tests/testFiles into tests/content_img_vfat_norm
* Comment out the other tests in tests/run.sh or populate those directories as
well
* Make sure to set the filename of the image and the kernel in `tests/run.sh`
* Run the tests:
```
sudo ./run_tests.sh
```
* If the image run processed images correctly but doesn't exit and unmount the
images cleanly, look at tests/run.exp and make sure it's waiting for the
string your qemu and kernel actually produce.

196
README_setup.md Normal file
View File

@ -0,0 +1,196 @@
Building the image from scratch
===============================
There is always a prebuilt image available for download and installation as
described in the [README](README.md). If you'd like to build the project yourself,
there are several steps involved:
* Downloading a generic Raspbian Lite image
* Adding space to the image
* Downloading and building the dependencies
* Copying the project filesystem into the image
This procedure will only work on Ubuntu or Debian Linux. If you use MacOS or
Windows, the best option is to install Linux in a virtual machine using
something like VirtualBox.
Downloading the Raspbian image
==============================
* Get the most recent version of Raspbian Jessie Lite:
```
wget https://downloads.raspberrypi.org/raspbian_lite_latest
```
* Unpack it:
```
unzip XXXX-XX-XX-raspbian-jessie-lite.zip
```
Adding space to the image
=========================
* Use dd to add 2GB (2048 blocks at 1024k each). Using /dev/zero as the input
file yields an unlimited number of "0x00" bytes.
```
> dd if=/dev/zero bs=1024k count=2048 >> XXXX-XX-XX-raspbian-jessie-lite.img
```
* Grow the root partition using fdisk. The "p" command prints the current partition
table. The first partition listed is the boot partition, which shouldn't be changed.
The "d" command, when given the parameter "2", deletes the current root partition.
The "n" command then makes a new partition. It can take the default for "type"
and "number". The "First sector" should be the value that was the "start" sector of the root
partition (131072 in the example below, but this varies depending on the version of the
Raspbian image). The "Last sector" should be the default, and it should be significantly
larger than it was before (6852607 vs. 2658303 in the example).
```
> fdisk XXXX-XX-XX-raspbian-jessie-lite.img
Command (m for help): *p*
Disk XXXX-XX-XX-raspbian-jessie-lite.img: 3.3 GiB, 3508535296 bytes, 6852608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x6f92008e
Device Boot Start End Sectors Size Id Type
XXXX-XX-XX-raspbian-jessie-lite.img1 8192 131071 122880 60M c W95 FAT32 (LBA)
XXXX-XX-XX-raspbian-jessie-lite.img2 131072 2658303 2527232 1.2G 83 Linux
Command (m for help): *d*
Partition number (1,2, default 2): *2*
Partition 2 has been deleted.
Command (m for help): *n*
Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p):
Using default response p.
Partition number (2-4, default 2):
First sector (2048-6852607, default 2048): *131072*
Last sector, +sectors or +size{K,M,G,T,P} (131072-6852607, default 6852607):
Created a new partition 2 of type 'Linux' and of size 3.2 GiB.
Command (m for help): *w*
The partition table has been altered.
Syncing disks.
```
* Mount the image in loop mode: first, edit /mount_image.sh to use the proper values
for $OFFSET_BOOT and $OFFSET_ROOTFS, which you can obtain using fdisk and "p" as
shown above. You must also change $IMAGE to the correct path. Then run:
```
sudo ./proper_chroot.sh
```
* After mounting the image, the above script will chroot into the mounted image.
While in a chroot, the / directory of the image appears as the system / directory
(thus the name, change root). To exit the chroot, run "exit" in the root directory.
Then, verify the path to the mounted partitions, and resize the filesystem
to fill the new larger partition using resize2fs:
```
> df | grep /mnt/arm
/dev/loop0 3927752 1955672 1794172 53% /mnt/arm_rPi
/dev/loop1 57288 18960 38328 34% /mnt/arm_rPi/boot
> sudo resize2fs /dev/loop0
```
Installing the dependencies
===========================
* To install the dependencies, you'll have to reenter the chroot again:
```
sudo chroot /mnt/arm_rPi
```
* Change your user to root (your global variables may be broken as a result):
```
su root
```
* Change the locales (remove "en_GB.UTF-8 UTF-8", add "en_US.UTF-8 UTF-8"). The
arrow keys move the cursor, spacebar selects/deselects a locale, tab moves the cursor
to a different context, and enter lets you select "ok":
```
dpkg-reconfigure locales
```
* In the image, make sure everything is up-to-date and remove the old packages:
```
apt-get update
apt-get dist-upgrade
apt-get autoremove
apt-get install timidity git p7zip-full python-dev python-pip python-lxml pmount libjpeg-dev libtiff-dev libwebp-dev liblcms2-dev tcl-dev tk-dev python-tk libxml2-dev libxslt1-dev
```
* Install the Python dependencies for PyCIRCLean. Currently, PyCIRCLean is
Python 2.7 and 3.3+ compatible, but Python 2 support might be dropped at some point.
```
pip install oletools olefile exifread Pillow
pip install git+https://github.com/Rafiot/officedissector.git
pip install git+https://github.com/CIRCL/PyCIRCLean.git
```
* Create a new user and make mounting work with a read-only filesystem.
```
useradd -m kitten
chown -R kitten:kitten /home/kitten
ln -s /proc/mounts /etc/mtab
```
* Enable rc.local, which ensures that the code in /etc/rc.local is run on boot.
This is what triggers CIRCLean to run.
```
systemctl enable rc-local.service
```
* Exit the chroot again, and copy the files from your repository into the mounted
image.
```
sudo ./copy_to_final.sh /mnt/arm_rPi/
```
Write the image on a SD card
============================
* Plug your SD card into the computer. Then, find where it is mounted using df:
```
df -h
```
* If it has been automatically mounted, unmount the SD card (use the path you
found in the previous step):
```
umount $PATH_TO_YOUR_SD
```
* Write the image to the card:
```
sudo dd bs=4M if=$PATH_TO_YOUR_IMAGE of=$PATH_TO_YOUR_SD
```

View File

View File

View File

@ -1,6 +0,0 @@
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat ro,defaults 0 0
/dev/mmcblk0p2 / ext4 ro,defaults,noatime 0 0
tmpfs /tmp tmpfs rw,size=64M,noexec,nodev,nosuid,mode=1777 0 0
tmpfs /media tmpfs rw,size=64M,noexec,nodev,nosuid,mode=1777 0 0
# a swapfile is not a swap partition, so no using swapon|off from here on, use dphys-swapfile swap[on|off] for that

View File

@ -1,54 +0,0 @@
root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:pi
tty:x:5:
disk:x:6:
lp:x:7:
mail:x:8:
news:x:9:
uucp:x:10:
man:x:12:
proxy:x:13:
kmem:x:15:
dialout:x:20:pi
fax:x:21:
voice:x:22:
cdrom:x:24:pi
floppy:x:25:
tape:x:26:
sudo:x:27:pi
audio:x:29:pi
dip:x:30:
www-data:x:33:
backup:x:34:
operator:x:37:
list:x:38:
irc:x:39:
src:x:40:
gnats:x:41:
shadow:x:42:
utmp:x:43:
video:x:44:pi
sasl:x:45:
plugdev:x:46:pi,kitten
staff:x:50:
games:x:60:pi
users:x:100:pi
nogroup:x:65534:
libuuid:x:101:
crontab:x:102:
pi:x:1000:
ssh:x:103:
ntp:x:104:
netdev:x:105:pi
input:x:999:pi
messagebus:x:106:
lpadmin:x:107:
fuse:x:108:
lightdm:x:109:
indiecity:x:1001:root
spi:x:1002:pi
gpio:x:1003:pi
kitten:x:1004:

View File

@ -1,5 +0,0 @@
# /etc/pmount.allow
# pmount will allow users to additionally mount all devices that are
# listed here.
/dev/sdb1
/dev/sda*

View File

@ -1,19 +0,0 @@
#!/bin/sh
# Part of raspi-config http://github.com/asb/raspi-config
#
# See LICENSE file for copyright and license details
# Should be installed to /etc/profile.d/raspi-config.sh to force raspi-config
# to run at initial login
# You may also want to set automatic login in /etc/inittab on tty1 by adding a
# line such as:
# 1:2345:respawn:/bin/login -f root tty1 </dev/tty1 >/dev/tty1 2>&1 # RPICFG_TO_DISABLE
if [ $(id -u) -ne 0 ]; then
printf "\nNOTICE: the software on this Raspberry Pi has not been fully configured. Please run 'sudo raspi-config'\n\n"
else
# Disable raspi-config at the first run.
# raspi-config
exec login -f pi
fi

View File

@ -1,36 +0,0 @@
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
clean(){
echo 'Rc Local done, quit.'
/sbin/shutdown -P -h now
}
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
if [ -e /dev/sda ]; then
if [ -e /dev/sdb ]; then
# avoid possible misuse
/sbin/ifconfig eth0 down
trap clean EXIT TERM INT
cd /opt/groomer
/usr/sbin/led &
./init.sh
fi
fi
exit 0

View File

@ -1 +0,0 @@
kitten hard priority -20

View File

@ -1,28 +0,0 @@
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# Host alias specification
# User alias specification
# Cmnd alias specification
# User privilege specification
#root ALL=(ALL:ALL) ALL
# Allow members of group sudo to execute any command
#%sudo ALL=(ALL:ALL) ALL
# See sudoers(5) for more information on "#include" directives:
#includedir /etc/sudoers.d
#pi ALL=(ALL) NOPASSWD: ALL

View File

@ -1 +0,0 @@
SUBSYSTEM=="hidraw", DRIVERS=="usbhid", RUN+="/bin/bash -c 'cd /sys/devices/platform/bcm2708_usb/usb1/1-1 ; for d in $(ls -d 1-1.[2-5]); do if [ $(ls -lR $d | grep -c usbhid) -gt 0 ] ; then echo 0 > $d/authorized ; fi ; done'"

View File

@ -1,2 +0,0 @@
KERNEL=="sdc", SYMLINK+="mmcblk0"
KERNEL=="sdc?", SYMLINK+="mmcblk0p%n",

View File

@ -1,23 +0,0 @@
DEV_SRC='/dev/sda'
DEV_DST='sdb1'
# User allowed to do the following commands without password
USERNAME='kitten'
MUSIC="/opt/midi/"
ID=`/usr/bin/id -u`
# Paths used in multiple scripts
SRC="src"
DST="dst"
TEMP="/media/${DST}/temp"
ZIPTEMP="/media/${DST}/ziptemp"
LOGS="/media/${DST}/logs"
# commands
SYNC='/bin/sync'
TIMIDITY='/usr/bin/timidity'
MOUNT='/bin/mount'
PMOUNT='/usr/bin/pmount -A -s'
PUMOUNT='/usr/bin/pumount'

View File

@ -1,4 +0,0 @@
# Paths to the commands used to convert the files
PDF="/usr/bin/pdf2htmlEX"
LO="/usr/bin/libreoffice"
UNPACKER="/usr/bin/7z"

View File

@ -1,332 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import magic
import os
import mimetypes
import shlex
import subprocess
import time
from helpers import FileBase, KittenGroomerBase, main
UNOCONV = '/usr/bin/unoconv'
LIBREOFFICE = '/usr/bin/libreoffice'
GS = '/usr/bin/gs'
PDF2HTMLEX = '/usr/bin/pdf2htmlEX'
SEVENZ = '/usr/bin/7z'
# Prepare application/<subtype>
mimes_office = ['msword', 'vnd.openxmlformats-officedocument.', 'vnd.ms-',
'vnd.oasis.opendocument']
mimes_pdf = ['pdf']
mimes_xml = ['xml']
mimes_ms = ['x-dosexec']
mimes_compressed = ['zip', 'x-rar', 'x-bzip2', 'x-lzip', 'x-lzma', 'x-lzop',
'x-xz', 'x-compress', 'x-gzip', 'x-tar', 'compressed']
mimes_data = ['octet-stream']
class File(FileBase):
def __init__(self, src_path, dst_path):
''' Init file object, set the mimetype '''
super(File, self).__init__(src_path, dst_path)
mimetype = magic.from_file(src_path, mime=True)
self.main_type, self.sub_type = mimetype.split('/')
self.log_details.update({'maintype': self.main_type, 'subtype': self.sub_type})
self.expected_mimetype, self.expected_extensions = self.crosscheck_mime()
self.is_recursive = False
def crosscheck_mime(self):
'''
Set the expected mime and extension variables based on mime type.
'''
# /usr/share/mime has interesting stuff
# guess_type uses the extension to get a mime type
expected_mimetype, encoding = mimetypes.guess_type(self.src_path, strict=False)
if expected_mimetype is not None:
expected_extensions = mimetypes.guess_all_extensions(expected_mimetype,
strict=False)
else:
# the extension is unknown...
expected_extensions = None
return expected_mimetype, expected_extensions
def verify_extension(self):
'''Check if the extension is the one we expect'''
if self.expected_extensions is None:
return None
path, actual_extension = os.path.splitext(self.src_path)
return actual_extension in self.expected_extensions
def verify_mime(self):
'''Check if the mime is the one we expect'''
if self.expected_mimetype is None:
return None
actual_mimetype = '{}/{}'.format(self.main_type, self.sub_type)
return actual_mimetype == self.expected_mimetype
class KittenGroomer(KittenGroomerBase):
def __init__(self, root_src=None, root_dst=None, max_recursive=5):
'''
Initialize the basics of the conversion process
'''
if root_src is None:
root_src = os.path.join(os.sep, 'media', 'src')
if root_dst is None:
root_dst = os.path.join(os.sep, 'media', 'dst')
super(KittenGroomer, self).__init__(root_src, root_dst)
self.recursive = 0
self.max_recursive = max_recursive
subtypes_apps = [
(mimes_office, self._office_related),
(mimes_pdf, self._pdf),
(mimes_xml, self._office_related),
(mimes_ms, self._executables),
(mimes_compressed, self._archive),
(mimes_data, self._binary_app),
]
self.subtypes_application = self._init_subtypes_application(subtypes_apps)
self.mime_processing_options = {
'text': self.text,
'audio': self.audio,
'image': self.image,
'video': self.video,
'application': self.application,
'example': self.example,
'message': self.message,
'model': self.model,
'multipart': self.multipart,
'inode': self.inode,
}
# Dirty trick to run libreoffice at least once and avoid unoconv to crash...
self._run_process(LIBREOFFICE, 5)
# ##### Helpers #####
def _init_subtypes_application(self, subtypes_application):
'''
Create the Dict to pick the right function based on the sub mime type
'''
to_return = {}
for list_subtypes, fct in subtypes_application:
for st in list_subtypes:
to_return[st] = fct
return to_return
def _print_log(self):
'''
Print the logs related to the current file being processed
'''
tmp_log = self.log_name.fields(**self.cur_file.log_details)
if self.cur_file.log_details.get('dangerous'):
tmp_log.warning(self.cur_file.log_string)
elif self.cur_file.log_details.get('unknown') or self.cur_file.log_details.get('binary'):
tmp_log.info(self.cur_file.log_string)
else:
tmp_log.debug(self.cur_file.log_string)
def _run_process(self, command_line, timeout=0):
'''Run subprocess, wait until it finishes'''
if timeout != 0:
deadline = time.time() + timeout
else:
deadline = None
args = shlex.split(command_line)
p = subprocess.Popen(args)
while True:
code = p.poll()
if code is not None:
break
if deadline is not None and time.time() > deadline:
p.kill()
break
time.sleep(1)
return True
#######################
# ##### Discarded mime types, reason in the comments ######
def inode(self):
''' Usually empty file. No reason (?) to copy it on the dest key'''
self.cur_file.log_string += 'Inode file'
def unknown(self):
''' This main type is unknown, that should not happen '''
self.cur_file.log_string += 'Unknown file'
# ##### Threated as malicious, no reason to have it on a USB key ######
def example(self):
'''Way to process example file'''
self.cur_file.log_string += 'Example file'
self.cur_file.make_dangerous()
self._safe_copy()
def message(self):
'''Way to process message file'''
self.cur_file.log_string += 'Message file'
self.cur_file.make_dangerous()
self._safe_copy()
def model(self):
'''Way to process model file'''
self.cur_file.log_string += 'Model file'
self.cur_file.make_dangerous()
self._safe_copy()
def multipart(self):
'''Way to process multipart file'''
self.cur_file.log_string += 'Multipart file'
self.cur_file.make_dangerous()
self._safe_copy()
#######################
# ##### Converted ######
def text(self):
''' LibreOffice should be able to open all the files '''
self.cur_file.log_string += 'Text file'
self._office_related()
def application(self):
''' Everything can be there, using the subtype to decide '''
for subtype, fct in list(self.subtypes_application.items()):
if subtype in self.cur_file.sub_type:
fct()
self.cur_file.log_string += 'Application file'
return
self.cur_file.log_string += 'Unknown Application file'
self._unknown_app()
def _executables(self):
'''Way to process executable file'''
self.cur_file.add_log_details('processing_type', 'executable')
self.cur_file.make_dangerous()
self._safe_copy()
def _office_related(self):
'''Way to process all the files LibreOffice can handle'''
self.cur_file.add_log_details('processing_type', 'office')
dst_dir, filename = os.path.split(self.cur_file.dst_path)
tmpdir = os.path.join(dst_dir, 'temp')
name, ext = os.path.splitext(filename)
tmppath = os.path.join(tmpdir, name + '.pdf')
self._safe_mkdir(tmpdir)
lo_command = '{} --format pdf -eSelectPdfVersion=1 --output {} {}'.format(
UNOCONV, tmppath, self.cur_file.src_path)
self._run_process(lo_command)
self._pdfa(tmppath)
self._safe_rmtree(tmpdir)
def _pdfa(self, tmpsrcpath):
'''Way to process PDF/A file'''
pdf_command = '{} --dest-dir / {} {}'.format(PDF2HTMLEX, tmpsrcpath,
self.cur_file.dst_path + '.html')
self._run_process(pdf_command)
def _pdf(self):
'''Way to process PDF file'''
self.cur_file.add_log_details('processing_type', 'pdf')
dst_dir, filename = os.path.split(self.cur_file.dst_path)
tmpdir = os.path.join(dst_dir, 'temp')
tmppath = os.path.join(tmpdir, filename)
self._safe_mkdir(tmpdir)
gs_command = '{} -dPDFA -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile={} {}'.format(
GS, tmppath, self.cur_file.src_path)
self._run_process(gs_command)
self._pdfa(tmppath)
self._safe_rmtree(tmpdir)
def _archive(self):
'''Way to process Archive'''
self.cur_file.add_log_details('processing_type', 'archive')
self.cur_file.is_recursive = True
self.cur_file.log_string += 'Archive extracted, processing content.'
tmpdir = self.cur_file.dst_path + '_temp'
self._safe_mkdir(tmpdir)
extract_command = '{} -p1 x {} -o{} -bd'.format(SEVENZ, self.cur_file.src_path, tmpdir)
self._run_process(extract_command)
self.recursive += 1
self.processdir(tmpdir, self.cur_file.dst_path)
self.recursive -= 1
self._safe_rmtree(tmpdir)
def _unknown_app(self):
'''Way to process an unknown file'''
self.cur_file.make_unknown()
self._safe_copy()
def _binary_app(self):
'''Way to process an unknown binary file'''
self.cur_file.make_binary()
self._safe_copy()
#######################
# ##### Not converted, checking the mime type ######
def audio(self):
'''Way to process an audio file'''
self.cur_file.log_string += 'Audio file'
self._media_processing()
def image(self):
'''Way to process an image'''
self.cur_file.log_string += 'Image file'
self._media_processing()
def video(self):
'''Way to process a video'''
self.cur_file.log_string += 'Video file'
self._media_processing()
def _media_processing(self):
'''Generic way to process all the media files'''
self.cur_log.fields(processing_type='media')
if not self.cur_file.verify_mime() or not self.cur_file.verify_extension():
# The extension is unknown or doesn't match the mime type => suspicious
# TODO: write details in the logfile
self.cur_file.make_dangerous()
self._safe_copy()
#######################
def processdir(self, src_dir=None, dst_dir=None):
'''
Main function doing the processing
'''
if src_dir is None:
src_dir = self.src_root_dir
if dst_dir is None:
dst_dir = self.dst_root_dir
if self.recursive > 0:
self._print_log()
if self.recursive >= self.max_recursive:
self.cur_log.warning('ARCHIVE BOMB.')
self.cur_log.warning('The content of the archive contains recursively other archives.')
self.cur_log.warning('This is a bad sign so the archive is not extracted to the destination key.')
self._safe_rmtree(src_dir)
if src_dir.endswith('_temp'):
archbomb_path = src_dir[:-len('_temp')]
self._safe_remove(archbomb_path)
for srcpath in self._list_all_files(src_dir):
self.cur_file = File(srcpath, srcpath.replace(src_dir, dst_dir))
self.log_name.info('Processing {} ({}/{})', srcpath.replace(src_dir + '/', ''),
self.cur_file.main_type, self.cur_file.sub_type)
self.mime_processing_options.get(self.cur_file.main_type, self.unknown)()
if not self.cur_file.is_recursive:
self._print_log()
if __name__ == '__main__':
main(KittenGroomer)

View File

@ -1,221 +0,0 @@
#!/bin/bash
source ./constraint.sh
source ./constraint_conv.sh
RECURSIVE_ARCHIVE_MAX=3
RECURSIVE_ARCHIVE_CURRENT=0
ARCHIVE_BOMB=0
LOGFILE="${LOGS}/processing.txt"
# Something went wrong.
error_handler(){
echo "FAILED." >> ${LOGFILE}
echo -e "\tSomething went wrong during the duplication of the last file." >> ${LOGFILE}
echo -e "\tPlease open a bug on https://www.github.com/Rafiot/KittenGroomer" >> ${LOGFILE}
continue
}
trap error_handler ERR TERM INT
office_n_txt(){
src_file=${1}
dst_file=${2}${1##$CURRENT_SRC}.html
temp=${2}/temp
${LO} --headless --convert-to pdf --outdir "${temp}" "${src_file}"
${PDF} --dest-dir=/ ${temp}/*.pdf ${dst_file}
rm -rf "${temp}"
}
copy(){
src_file=${1}
dst_file=${2}
mkdir -p `dirname "${dst_file}"`
cp "${src_file}" "${dst_file}"
}
# Plain text
text(){
echo Text file ${1}
office_n_txt ${1} ${2}
}
# Multimedia
## WARNING: They are assumed safe.
audio(){
echo Audio file ${1}
copy ${1} ${2}${1##$CURRENT_SRC}
}
image(){
echo Image file ${1}
copy ${1} ${2}${1##$CURRENT_SRC}
}
video(){
echo Video file ${1}
copy ${1} ${2}${1##$CURRENT_SRC}
}
# Random - Used
archive(){
echo Archive file ${1}
if [ ${ARCHIVE_BOMB} -eq 0 ]; then
temp_extract_dir=${2}_temp
mkdir -p "${temp_extract_dir}"
${UNPACKER} -p1 x "${1}" -o"${temp_extract_dir}" -bd
main ${2} ${RECURSIVE_ARCHIVE_CURRENT} ${temp_extract_dir} || true
rm -rf "${temp_extract_dir}"
fi
if [ ${ARCHIVE_BOMB} -eq 1 ]; then
rm -rf "${2}"
rm -rf "${2}_temp"
fi
CURRENT_SRC="/media/${SRC}"
}
application(){
echo App file ${1}
src_file=${1}
dst_file=${2}${1##$CURRENT_SRC}
mime_details=${3}
case ${mime_details} in
pdf)
echo "Got a pdf"
${PDF} --dest-dir "${2}" "${src_file}"
;;
msword|vnd.openxmlformats-officedocument.*|vnd.ms-*|vnd.oasis.opendocument*)
# https://blogs.msdn.com/b/vsofficedeveloper/archive/2008/05/08/office-2007-open-xml-mime-types.aspx
# http://plan-b-for-openoffice.org/glossary/term/mime-type
echo "MS Office or ODF document"
office_n_txt ${src_file} ${2}
;;
*xml*)
echo "Got an XML"
office_n_txt ${src_file} ${2}
;;
x-dosexec)
echo "Win executable"
copy ${src_file} ${2}/DANGEROUS_${1##$CURRENT_SRC/}_DANGEROUS
;;
zip|x-rar|x-bzip2|x-lzip|x-lzma|x-lzop|x-xz|x-compress|x-gzip|x-tar|*compressed)
echo "Compressed file"
archive ${src_file} ${dst_file}
;;
octet-stream)
echo "Unknown type."
copy ${src_file} ${dst_file}.bin
;;
*)
echo "Unhandled type"
copy ${src_file} ${dst_file}
;;
esac
}
# Random - Unused?
## WARNING: They are assumed safe.
example(){
echo Example file ${1}
copy ${1} ${2}${1##$CURRENT_SRC}
}
message(){
echo Message file ${1}
copy ${1} ${2}${1##$CURRENT_SRC}
}
model(){
echo Model file ${1}
copy ${1} ${2}${1##$CURRENT_SRC}
}
multipart(){
echo Multipart file ${1}
copy ${1} ${2}${1##$CURRENT_SRC}
}
main(){
if [ -z ${1} ]; then
echo "Please specify the destination directory."
exit
fi
set -e
set -x
if [ -z ${2} ]; then
CURRENT_SRC="/media/${SRC}"
RECURSIVE_ARCHIVE_CURRENT=0
ARCHIVE_BOMB=0
else
RECURSIVE_ARCHIVE_CURRENT=${2}
CURRENT_SRC=${3}
if [ ${RECURSIVE_ARCHIVE_CURRENT} -gt ${RECURSIVE_ARCHIVE_MAX} ]; then
echo Archive bomb.
ARCHIVE_BOMB=1
echo "ARCHIVE BOMB." >> ${LOGFILE}
echo "The content of the archive contains recursively other archives." >> ${LOGFILE}
echo "This is a bad sign so the archive is not extracted to the destination key." >> ${LOGFILE}
return
else
RECURSIVE_ARCHIVE_CURRENT=`expr ${RECURSIVE_ARCHIVE_CURRENT} + 1`
fi
fi
FILE_LIST=`find ${CURRENT_SRC} -type f`
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for file in ${FILE_LIST}; do
# first param is the destination dir
dest=${1}
mime=`file -b --mime-type "${file}"`
echo ${mime}
main_mime=`echo ${mime} | cut -f1 -d/`
details=`echo ${mime} | cut -f2 -d/`
echo -n "Processing ${file} (${mime})... " >> ${LOGFILE}
case "${main_mime}" in
"text")
text ${file} ${dest} || error_handler
;;
"audio")
audio ${file} ${dest} || error_handler
;;
"image")
image ${file} ${dest} || error_handler
;;
"video")
video ${file} ${dest} || error_handler
;;
"application")
application ${file} ${dest} ${details} || error_handler
;;
"example")
example ${file} ${dest} || error_handler
;;
"message")
message ${file} ${dest} || error_handler
;;
"model")
model ${file} ${dest} || error_handler
;;
"multipart")
multipart ${file} ${dest} || error_handler
;;
*)
echo "This should never happen... :]"
echo $mime $main_mime $details
;;
esac
echo "done." >> ${LOGFILE}
done
IFS=$SAVEIFS
return 0
}

View File

@ -1,68 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from helpers import FileBase, KittenGroomerBase, main
printers = ['.STL', '.obj']
cnc = ['.nc', '.tap', '.gcode', '.dxf', '.stl', '.obj', '.iges', '.igs',
'.vrml', '.vrl', '.thing', '.step', '.stp', '.x3d']
shopbot = ['.ai', '.svg', '.dxf', '.dwg', '.eps']
omax = ['.ai', '.svg', '.dxf', '.dwg', '.eps', '.omx', '.obj']
epilog_laser = ['.ai', '.svg', '.dxf', '.dwg', '.eps']
metabeam = ['.dxf']
up = ['.upp', '.up3', '.stl', '.obj']
class FilePier9(FileBase):
def __init__(self, src_path, dst_path):
''' Init file object, set the extension '''
super(FilePier9, self).__init__(src_path, dst_path)
a, self.extension = os.path.splitext(self.src_path)
class KittenGroomerPier9(KittenGroomerBase):
def __init__(self, root_src=None, root_dst=None):
'''
Initialize the basics of the copy
'''
if root_src is None:
root_src = os.path.join(os.sep, 'media', 'src')
if root_dst is None:
root_dst = os.path.join(os.sep, 'media', 'dst')
super(KittenGroomerPier9, self).__init__(root_src, root_dst)
# The initial version will accept all the file extension for all the machines.
self.authorized_extensions = printers + cnc + shopbot + omax + epilog_laser + metabeam + up
def _print_log(self):
'''
Print the logs related to the current file being processed
'''
tmp_log = self.log_name.fields(**self.cur_file.log_details)
if not self.cur_file.log_details.get('valid'):
tmp_log.warning(self.cur_file.log_string)
else:
tmp_log.debug(self.cur_file.log_string)
def processdir(self):
'''
Main function doing the processing
'''
for srcpath in self._list_all_files(self.src_root_dir):
self.log_name.info('Processing {}', srcpath.replace(self.src_root_dir + '/', ''))
self.cur_file = FilePier9(srcpath, srcpath.replace(self.src_root_dir, self.dst_root_dir))
if self.cur_file.extension in self.authorized_extensions:
self.cur_file.add_log_details('valid', True)
self.cur_file.log_string = 'Expected extension: ' + self.cur_file.extension
self._safe_copy()
else:
self.cur_file.log_string = 'Bad extension: ' + self.cur_file.extension
self._print_log()
if __name__ == '__main__':
main(KittenGroomerPier9)

View File

@ -1,122 +0,0 @@
#!/bin/bash
set -e
set -x
# To make debugging easier
echo "KittenGroomer: in groomer.sh" 1>&2
source ./constraint.sh
if ! [ "${ID}" -ge "1000" ]; then
echo "This script cannot run as root."
exit
fi
source ./functions.sh
clean(){
echo Cleaning.
${SYNC}
# Cleanup source
pumount ${SRC}
# Cleanup destination
rm -rf ${TEMP}
rm -rf ${ZIPTEMP}
pumount ${DST}
exit
}
trap clean EXIT TERM INT
# De we have a source device
if [ ! -b ${DEV_SRC} ]; then
echo "Source device (${DEV_SRC}) does not exists."
exit
fi
# Find the partition names on the source device
DEV_PARTITIONS=`ls "${DEV_SRC}"* | grep "${DEV_SRC}[1-9][0-6]*" || true`
if [ -z "${DEV_PARTITIONS}" ]; then
echo "${DEV_SRC} does not have any partitions."
exit
fi
# Do we have a destination device
if [ ! -b "/dev/${DEV_DST}" ]; then
echo "Destination device (/dev/${DEV_DST}) does not exists."
exit
fi
# mount and prepare destination device
if ${MOUNT}|grep ${DST}; then
${PUMOUNT} ${DST} || true
fi
# uid= only works on a vfat FS. What should wedo if we get an ext* FS ?
${PMOUNT} -w ${DEV_DST} ${DST}
if [ ${?} -ne 0 ]; then
echo "Unable to mount /dev/${DEV_DST} on /media/${DST}"
exit
else
echo "Target USB device (/dev/${DEV_DST}) mounted at /media/${DST}"
rm -rf "/media/${DST}/FROM_PARTITION_"*
# prepare temp dirs and make sure it's empty
mkdir -p "${TEMP}"
mkdir -p "${ZIPTEMP}"
mkdir -p "${LOGS}"
rm -rf "${TEMP}/"*
rm -rf "${ZIPTEMP}/"*
rm -rf "${LOGS}/"*
fi
# Groom da kitteh!
# Find the FS types
# lsblk -n -o name,fstype,mountpoint,label,uuid -r
PARTCOUNT=1
for partition in ${DEV_PARTITIONS}
do
# Processing a partition
echo "Processing partition: ${partition}"
if [ `${MOUNT} | grep -c ${SRC}` -ne 0 ]; then
${PUMOUNT} ${SRC}
fi
${PMOUNT} -w ${partition} ${SRC}
ls "/media/${SRC}" | grep -i autorun.inf | xargs -I {} mv "/media/${SRC}"/{} "/media/${SRC}"/DANGEROUS_{}_DANGEROUS || true
${PUMOUNT} ${SRC}
${PMOUNT} -r ${partition} ${SRC}
if [ ${?} -ne 0 ]; then
echo "Unable to mount ${partition} on /media/${SRC}"
else
echo "${partition} mounted at /media/${SRC}"
# Print the filenames on the current partition in a logfile
find "/media/${SRC}" -fls "${LOGS}/Content_partition_${PARTCOUNT}.txt"
# create a directory on ${DST} named PARTION_$PARTCOUNT
target_dir="/media/${DST}/FROM_PARTITION_${PARTCOUNT}"
echo "copying to: ${target_dir}"
mkdir -p "${target_dir}"
LOGFILE="${LOGS}/processing.txt"
echo "==== Starting processing of /media/${SRC} to ${target_dir}. ====" 1>&2
echo "==== Starting processing of /media/${SRC} to ${target_dir}. ====" >> ${LOGFILE}
generic.py --source /media/${SRC} --destination ${target_dir} || true
echo "==== Done with /media/${SRC} to ${target_dir}. ====" 1>&2
echo "==== Done with /media/${SRC} to ${target_dir}. ====" >> ${LOGFILE}
ls -lR "${target_dir}"
fi
let PARTCOUNT=`expr $PARTCOUNT + 1`
done
# To make debugging easier
echo "KittenGroomer: done with groomer.sh" 1>&2
# The cleanup is automatically done in the function clean called when
# the program quits

View File

@ -1,149 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import shutil
from twiggy import quickSetup, log
import argparse
class KittenGroomerError(Exception):
def __init__(self, message):
'''
Base KittenGroomer exception handler.
'''
super(KittenGroomerError, self).__init__(message)
self.message = message
class ImplementationRequired(KittenGroomerError):
'''
Implementation required error
'''
pass
class FileBase(object):
def __init__(self, src_path, dst_path):
'''
Contains base information for a file on the source USB key,
initialised with expected src and dest path
'''
self.src_path = src_path
self.dst_path = dst_path
self.log_details = {'filepath': self.src_path}
self.log_string = ''
def add_log_details(self, key, value):
'''
Add an entry in the log dictionary
'''
self.log_details[key] = value
def make_dangerous(self):
'''
This file should be considered as dangerous and never run.
Prepending and appending DANGEROUS to the destination
file name avoid double-click of death
'''
self.log_details['dangerous'] = True
path, filename = os.path.split(self.dst_path)
self.dst_path = os.path.join(path, 'DANGEROUS_{}_DANGEROUS'.format(filename))
def make_unknown(self):
'''
This file has an unknown type and it was not possible to take
a decision. Theuser will have to decide what to do.
Prepending UNKNOWN
'''
self.log_details['unknown'] = True
path, filename = os.path.split(self.dst_path)
self.dst_path = os.path.join(path, 'UNKNOWN_{}'.format(filename))
def make_binary(self):
'''
This file is a binary, and should probably not be run.
Appending .bin avoir double click of death but the user
will have to decide by itself.
'''
self.log_details['binary'] = True
path, filename = os.path.split(self.dst_path)
self.dst_path = os.path.join(path, '{}.bin'.format(filename))
class KittenGroomerBase(object):
def __init__(self, root_src, root_dst):
'''
Setup the base options of the copy/convert setup
'''
self.src_root_dir = root_src
self.dst_root_dir = root_dst
self.log_root_dir = os.path.join(self.dst_root_dir, 'logs')
self.log_processing = os.path.join(self.log_root_dir, 'processing.log')
# quickSetup(file=self.log_processing)
quickSetup()
self.log_name = log.name('files')
self.cur_file = None
# ##### Helpers #####
def _safe_rmtree(self, directory):
'''Remove a directory tree if it exists'''
if os.path.exists(directory):
shutil.rmtree(directory)
def _safe_remove(self, filepath):
'''Remove a file if it exists'''
if os.path.exists(filepath):
os.remove(filepath)
def _safe_mkdir(self, directory):
'''Remove a directory if it exists'''
if not os.path.exists(directory):
os.makedirs(directory)
def _safe_copy(self):
''' Copy a file and create directory if needed '''
try:
dst_path, filename = os.path.split(self.cur_file.dst_path)
self._safe_mkdir(dst_path)
shutil.copy(self.cur_file.src_path, self.cur_file.dst_path)
return True
except Exception as e:
# TODO: Logfile
print(e)
return False
def _list_all_files(self, directory):
''' Generate an iterator over all the files in a directory tree '''
for root, dirs, files in os.walk(directory):
for filename in files:
filepath = os.path.join(root, filename)
yield filepath
def _print_log(self):
'''
Print log, should be called after each file.
You probably want to reimplement it in the subclass
'''
tmp_log = self.log_name.fields(**self.cur_file.log_details)
tmp_log.info('It did a thing.')
#######################
def processdir(self, src_dir=None, dst_dir=None):
'''
Main function doing the work, you have to implement it yourself.
'''
raise ImplementationRequired('You have to implement the result processdir.')
def main(kg_implementation):
parser = argparse.ArgumentParser(prog='KittenGroomer', description='Call the KittenGroomer implementation to do things on files present in the source directory to the destination directory')
parser.add_argument('-s', '--source', type=str, help='Source directory')
parser.add_argument('-d', '--destination', type=str, help='Destination directory')
args = parser.parse_args()
kg = kg_implementation(args.source, args.destination)
kg.processdir()

View File

@ -1,43 +0,0 @@
#!/bin/bash
set -e
set -x
source ./constraint.sh
if [ ${ID} -ne 0 ]; then
echo "This script has to be run as root."
exit
fi
clean(){
echo Done, cleaning.
${SYNC}
kill -9 $(cat /tmp/music.pid)
rm -f /tmp/music.pid
}
trap clean EXIT TERM INT
./music.sh &
echo $! > /tmp/music.pid
# Dumb libreoffice wants to write into ~/libreoffice or crash with
# com::sun::star::uno::RuntimeException
mkdir /tmp/libreoffice
chown -R kitten:kitten /tmp/libreoffice
# Avoid:
# Failed to connect to /usr/lib/libreoffice/program/soffice.bin (pid=2455) in 6 seconds.
# Connector : couldn't connect to socket (Success)
# Error: Unable to connect or start own listener. Aborting.
mkdir /tmp/libreoffice_config
chown -R kitten:kitten /tmp/libreoffice_config
# Reject all network connexions.
iptables -F
iptables -A INPUT -j REJECT
iptables -A OUTPUT -j REJECT
iptables -A FORWARD -j REJECT
su ${USERNAME} -c ./groomer.sh

View File

@ -1,21 +0,0 @@
#!/bin/bash
set -e
#set -x
source ./constraint.sh
killed(){
echo 'Music stopped.'
}
trap killed EXIT TERM INT
# Force output on analog
amixer cset numid=3 1
files=(${MUSIC}*)
while true; do
$TIMIDITY ${files[RANDOM % ${#files[@]}]}
done

View File

@ -10,6 +10,9 @@
# bits.
#
# By default this script does nothing.
#
# The above are the default comments for rc.local. For Circlean, rc.local has
# been modified to start the grooming process on boot.
clean(){
echo 'Rc Local done, quit.'

View File

@ -1,47 +0,0 @@
#!/usr/bin/env python3
from RPi import GPIO
import time
# blinking function
def blink(pin):
GPIO.output(pin, GPIO.HIGH)
time.sleep(.1)
GPIO.output(pin, GPIO.LOW)
time.sleep(.1)
return
def test_leds():
# to use Raspberry Pi board pin numbers
GPIO.setmode(GPIO.BOARD)
pins = [11, 12, 15]
# set up GPIO output channel
for pin in pins:
GPIO.setup(pin, GPIO.OUT)
# blink GPIO17 50 times
for i in range(0, 50):
for pin in pins:
blink(pin)
def test_button():
GPIO.setmode(GPIO.BCM)
button = 23
GPIO.setup(button, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
while True:
GPIO.wait_for_edge(button, GPIO.RISING)
print("Button Pressed")
GPIO.wait_for_edge(button, GPIO.FALLING)
print("Button Released")
test_button()
GPIO.cleanup()

View File

@ -1,13 +1,13 @@
#!/bin/bash
# This script will mount a given image or sd card in loop mode.
# Make sure to change the path and offsets for the image you use. You can get
# the correct offsets using `file $PATH_TO_IMAGE` or fdisk.
# If you want to mount an SD card, unset $IMAGE.
# To make debugging easier
echo "KittenGroomer: in mount_image.sh" 1>&2
# Notes:
# - To chroot in an existing SD card, unset IMAGE. Change the paths to the partitions if needed.
# - The offsets are thoses of 2013-02-09-wheezy-raspbian.img. It will change on an other image.
# To get the offsets, use the "file" command.
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
@ -33,21 +33,17 @@ PARTITION_BOOT='/dev/mmcblk0p1'
#PARTITION_ROOTFS='/dev/sdd2'
#PARTITION_BOOT='/dev/sdd1'
# If you use the img
# If you use the img...
# Double check the path and offsets as noted above!
##### Debian
IMAGE='2016-05-09_CIRCLean.img'
OFFSET_ROOTFS=$((131072 * 512))
OFFSET_BOOT=$((8192 * 512))
##### Arch
#IMAGE='archlinux-hf-2013-02-11.img'
#OFFSET_ROOTFS=$((186368 * 512))
#OFFSET_BOOT=$((2048 * 512))
############
OFFSET_ROOTFS=$((131072 * 512))
CHROOT_PATH='/mnt/arm_rPi'
clean(){
mv ${CHROOT_PATH}/etc/ld.so.preload_bkp ${CHROOT_PATH}/etc/ld.so.preload
mv ${CHROOT_PATH}/etc/ld.so.preload_backup ${CHROOT_PATH}/etc/ld.so.preload
rm ${CHROOT_PATH}/etc/resolv.conf
rm ${CHROOT_PATH}/usr/bin/qemu*arm*
@ -79,7 +75,7 @@ elif [ -a ${PARTITION_ROOTFS} ]; then
mount ${PARTITION_ROOTFS} ${CHROOT_PATH}
mount ${PARTITION_BOOT} ${CHROOT_PATH}/boot
else
print 'You need a SD card or an image'
echo 'You need a SD card or an image'
exit
fi
@ -95,7 +91,7 @@ mount -o bind /tmp ${CHROOT_PATH}/tmp
cp -pf /etc/resolv.conf ${CHROOT_PATH}/etc
mv ${CHROOT_PATH}/etc/ld.so.preload ${CHROOT_PATH}/etc/ld.so.preload_bkp
mv ${CHROOT_PATH}/etc/ld.so.preload ${CHROOT_PATH}/etc/ld.so.preload_backup
# To make debugging easier
echo "KittenGroomer: Image mounted, executing command from mount_image.sh" 1>&2

View File

@ -1,14 +0,0 @@
#!/bin/bash
# change locales to en_US.UTF-8
dpkg-reconfigure locales
# Increase size of image. See resize_img.md
apt-get update
apt-get dist-upgrade
apt-get autoremove
# build dependencies of pdf2htmlEX
apt-get install cmake debhelper libpoppler-dev libjpeg-dev libfontforge-dev \
libspiro-dev python-dev default-jre-headless libpoppler-private-dev

View File

@ -10,16 +10,6 @@ apt-get autoremove
apt-get install libreoffice p7zip-full libfontforge1 timidity freepats pmount
dpkg -i pdf2htmlex*.deb
# Make Libreoffice usable on a RO filesystem
useradd -m kitten
pushd /home/kitten
ln -s /tmp/libreoffice
popd
chown -R kitten:kitten /home/kitten
ln -s /proc/mounts /etc/mtab
# Disable swap
dphys-swapfile uninstall

View File

@ -1,11 +0,0 @@
#!/bin/bash
# We cannot use the version 0.12 because it requires fontforge 2.0
# The fork use a saner list of dependencies and a patch that allows to build on debian jessie.
wget https://github.com/Rafiot/pdf2htmlEX/archive/KittenGroomer.zip
unzip KittenGroomer.zip
cd pdf2htmlEX-KittenGroomer/
dpkg-buildpackage -uc -b