mirror of
https://github.com/Llewellynvdm/Tomb.git
synced 2024-11-10 23:20:57 +00:00
Compare commits
214 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ff692999de | ||
|
4783456814 | ||
|
653609a4b9 | ||
|
284fb4a3cd | ||
|
0ef195dff0 | ||
|
48c08c0086 | ||
|
29098f356c | ||
|
447817de6c | ||
|
b7fa057e48 | ||
|
963a0cc321 | ||
|
117bd9bd6e | ||
|
c1b5e1b310 | ||
|
afe0390d93 | ||
|
32eab3beec | ||
|
11a5776456 | ||
|
ef1541f7a2 | ||
|
73950fe3d8 | ||
|
41b899e4e1 | ||
|
33f7878a22 | ||
|
42e233d2b0 | ||
|
6df1cdeab9 | ||
|
0b25ba6d68 | ||
|
89283a06b7 | ||
|
c83068c03a | ||
|
be533b3995 | ||
|
75aafc0c8c | ||
|
45c4616110 | ||
|
7016515ce6 | ||
|
97c61dc513 | ||
|
4523823c48 | ||
|
cb997eec2c | ||
|
857895a750 | ||
|
891fa80c7a | ||
|
431f1c6647 | ||
|
2b75962e54 | ||
|
bae8af351b | ||
|
2082198b36 | ||
|
552dc82fe3 | ||
|
7ebcfc767e | ||
|
c72432d640 | ||
|
4a277c97f2 | ||
|
735d540fe7 | ||
|
b715917b31 | ||
|
0d06c994cf | ||
|
6c383ffd64 | ||
|
ddb2de6072 | ||
|
3398b7bf89 | ||
|
abe5704658 | ||
|
d0b84d78a0 | ||
|
91adbbe183 | ||
|
766cd27c1b | ||
|
dee2b0f8c4 | ||
|
13eeef7c6c | ||
|
194d60fe9a | ||
|
7f91cc917d | ||
|
09d981f0fc | ||
|
e1afecb832 | ||
|
e97c088a26 | ||
|
9385ddee43 | ||
27792f4421 | |||
8be3163022 | |||
|
21da75adab | ||
|
a0b633fb77 | ||
|
f9ec17d126 | ||
|
dcdf4cb3bb | ||
|
0c8d4cf477 | ||
|
51452e4e6a | ||
|
58035cf14a | ||
|
06ea734878 | ||
|
347462cb0c | ||
|
cd9fa46964 | ||
|
d8989e1955 | ||
|
59d7331cb0 | ||
|
4d72a2180a | ||
|
7249afe98e | ||
|
0eed3cf321 | ||
|
e316ef22cc | ||
|
82e5342334 | ||
|
4e3221e937 | ||
|
364a457fbc | ||
|
571cdeafbf | ||
|
b9cf58054a | ||
|
646d2c33fd | ||
|
713cfd3071 | ||
|
5eaa92e614 | ||
|
d65a3f1586 | ||
|
b5eae55c8b | ||
|
0130fcf86d | ||
|
30d2e92a77 | ||
|
0d004f312d | ||
|
b14be5022e | ||
|
ed841b9f32 | ||
|
6e8ef0a29a | ||
|
5772d39e19 | ||
|
1ae5845c61 | ||
|
fce89023a5 | ||
|
be911b1e16 | ||
|
12684e6740 | ||
|
42390b78c0 | ||
|
3639b2e0ec | ||
|
8502bdc722 | ||
|
e463a6e600 | ||
|
6af298e15f | ||
|
1655fd5a99 | ||
|
8782dab9ed | ||
|
3b44a6be3a | ||
|
7a1b699cea | ||
|
85af9459aa | ||
|
f4e2ae2f97 | ||
|
62806769af | ||
|
8be3e7d2a0 | ||
|
97343cf590 | ||
|
60034b0b55 | ||
|
b7822afaf0 | ||
|
6955719f04 | ||
|
8ceeca8769 | ||
|
03c93ef976 | ||
|
5a5eb6ddcf | ||
|
9323c1caf8 | ||
|
f7046c5941 | ||
|
b6ffe1a2f1 | ||
|
84ef4bef4b | ||
|
e0ba8c5f4d | ||
|
90eec3d830 | ||
|
930b414889 | ||
|
61a9d1a420 | ||
|
d2d35bc8db | ||
|
585af6a61b | ||
|
2a744fe89d | ||
|
b235f16ce4 | ||
|
ce521ed2e2 | ||
|
087ecd25a2 | ||
|
24a89b680d | ||
|
3860487a0b | ||
|
61386ca646 | ||
|
ae21619d04 | ||
|
7f2e22c517 | ||
|
fb3ffcec03 | ||
|
815b8f4218 | ||
|
f35ad11e3f | ||
|
c0d1a7584d | ||
|
c5701793fb | ||
|
02812f4c06 | ||
|
99f10bf215 | ||
|
859a5c7783 | ||
|
312915b4b3 | ||
|
d227695778 | ||
|
8d5a85658f | ||
|
0ac5a34c20 | ||
|
d8360688b3 | ||
|
7a81ad032d | ||
|
9f30f7da89 | ||
|
6d87b7e355 | ||
|
b6fff10c2a | ||
|
b0de6e07b2 | ||
|
5199bef4a6 | ||
|
45b144d213 | ||
|
c13f38266e | ||
|
285f3c3a07 | ||
|
0a968b80b7 | ||
|
694390bd4a | ||
|
da590fb50e | ||
|
c9f3b07cd8 | ||
|
f9d9d4bc8b | ||
|
c3a354cc0f | ||
|
3fb248bde8 | ||
|
940563d02c | ||
|
91debdbf58 | ||
|
c7b1f00370 | ||
|
bc94559ac4 | ||
|
b20ef50563 | ||
|
72da5b481e | ||
|
9be5dff823 | ||
|
59d3810665 | ||
|
d135730386 | ||
|
010674f30b | ||
|
193cd42bbd | ||
|
a1f2364eb8 | ||
|
763dbdb356 | ||
|
5b80abd96d | ||
|
136ba6e053 | ||
|
9ddfdc426f | ||
|
298eedfedf | ||
|
15c894dfb4 | ||
|
d3995b82db | ||
|
fb154bbb2f | ||
|
f14ba758ee | ||
|
85f02f746e | ||
|
2f29e6709c | ||
|
7cead041ac | ||
|
4ec85ea3ca | ||
|
7da034c146 | ||
|
ac13adaa28 | ||
|
e9fd1a19e1 | ||
|
377e335e93 | ||
|
bec53aeb72 | ||
|
2d8a72ed95 | ||
|
7e82beaca6 | ||
|
15d279605b | ||
|
ca708b4d46 | ||
|
d2cd41e1e7 | ||
|
382070481f | ||
|
01f5412fc5 | ||
|
1574723502 | ||
|
71a7241f9c | ||
|
94d8ad497f | ||
|
187a627022 | ||
|
6f2ce59d29 | ||
|
0b9080e0ca | ||
|
d83e39f1ec | ||
|
1a93481480 | ||
|
6b4bd69dbc | ||
|
0e9fe51b50 | ||
|
06039a9e47 |
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
github: dyne
|
||||
patreon: dyneorg
|
||||
open_collective: dyne
|
||||
|
76
.github/workflows/hugo.yml
vendored
Normal file
76
.github/workflows/hugo.yml
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
# Sample workflow for building and deploying a Hugo site to GitHub Pages
|
||||
name: Deploy Hugo site to Pages
|
||||
|
||||
on:
|
||||
# Runs on pushes targeting the default branch
|
||||
push:
|
||||
branches: ["website"]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
||||
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
# Default to bash
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
# Build job
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
HUGO_VERSION: 0.124.1
|
||||
steps:
|
||||
- name: Install Hugo CLI
|
||||
run: |
|
||||
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
|
||||
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
|
||||
- name: Install Dart Sass
|
||||
run: sudo snap install dart-sass
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Setup Pages
|
||||
id: pages
|
||||
uses: actions/configure-pages@v5
|
||||
- name: Install Node.js dependencies
|
||||
run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
|
||||
- name: Build with Hugo
|
||||
env:
|
||||
# For maximum backward compatibility with Hugo modules
|
||||
HUGO_ENVIRONMENT: production
|
||||
HUGO_ENV: production
|
||||
run: |
|
||||
hugo \
|
||||
--minify \
|
||||
--source docs \
|
||||
## breaks URL building ## --baseURL "${{ steps.pages.outputs.base_url }}/"
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: ./docs/public
|
||||
|
||||
# Deployment job
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
56
.github/workflows/linux.yml
vendored
Normal file
56
.github/workflows/linux.yml
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
name:
|
||||
💀 Linux Tomb
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'doc/**'
|
||||
- 'extras/portable/**'
|
||||
- '*.md'
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'doc/**'
|
||||
- 'extras/portable/**'
|
||||
- '*.md'
|
||||
branches:
|
||||
- master
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-matrix:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-20.04, ubuntu-24.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Install tomb dependencies
|
||||
run: |
|
||||
sudo apt-get update -y -q
|
||||
sudo apt-get install -y -q zsh cryptsetup gpg gawk libgcrypt20-dev steghide qrencode python3-pip python3-dev libssl-dev make gcc sudo gettext bsdmainutils file pinentry-curses xxd libsodium23 libsodium-dev argon2
|
||||
- name: Install python2 on ubuntu 20
|
||||
if: matrix.os == 'ubuntu-20.04'
|
||||
run: sudo apt-get install -y -q python2
|
||||
- name: Install python2 on ubuntu 22
|
||||
if: matrix.os == 'ubuntu-22.04'
|
||||
run: sudo apt-get install -y -q python2
|
||||
- name: Install doas where found
|
||||
if: matrix.os == 'ubuntu-24.04'
|
||||
run: |
|
||||
sudo apt-get install -y -q opendoas
|
||||
echo "permit nopass root" | sudo tee /etc/doas.conf
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build the pbkdf2 extras
|
||||
run: |
|
||||
make --directory=extras/kdf-keys
|
||||
sudo make --directory=extras/kdf-keys install
|
||||
- name: Run pbkdf2 tests
|
||||
run: sudo make -C extras/kdf-keys test
|
||||
- name: Disable swap
|
||||
run: sudo swapoff -a
|
||||
- name: Run main tests
|
||||
run: sudo make test
|
37
AUTHORS.md
37
AUTHORS.md
@ -2,39 +2,42 @@ Cryptsetup was originally written in 2004 by Jana Saout
|
||||
|
||||
LUKS extensions are written in 2006 by Clemens Fruhwirth
|
||||
|
||||
Tomb is written and maintained since 2007 by Denis Roio <jaromil@dyne.org>
|
||||
Tomb is written and maintained since 2007 by [Denis "Jaromil" Roio](https://jaromil.dyne.org)
|
||||
|
||||
Tomb includes code and advices by Anathema, Boyska, Hellekin O. Wolf,
|
||||
Daniel Rodriguez, Parazyd, Alexandre Pujol, AitorATuin, Narrat and
|
||||
Artur Malimonov.
|
||||
Daniel Rodriguez, Parazyd, Alexandre Pujol, AitorATuin, Narrat, Artur
|
||||
Malimonov and Chris Vogel.
|
||||
|
||||
The 'gtomb' GUI based on Zenity is written by Parazyd.
|
||||
The 'gtomb' GUI based on Zenity is written by Parazyd and Daniel Dias Rodrigues.
|
||||
|
||||
The Qt5 desktop tray GUI is written by Gianluca Montecchi.
|
||||
|
||||
Python Tomb wrappers are contributed by Reiven and Boyska.
|
||||
|
||||
The Docker Tomb wrapper is contributed by Greg Tczap and Jens Rischbieth.
|
||||
|
||||
Artwork is contributed by Jordi aka Mon Mort and Logan VanCuren.
|
||||
|
||||
Gettext internationalization and Spanish translation is contributed by
|
||||
Daniel Rodriguez. French translation by Hellekin and Roy Lockhart,
|
||||
Russian translation by fsLeg, German translation by Jerry Polfer,
|
||||
Italian translation by Massimiliano Augello and Swedish translation by
|
||||
PLJ / Kosovoper.
|
||||
Daniel Rodriguez and Francisco Serrador. French translation by
|
||||
Hellekin and Roy Lockhart, Russian translation by fsLeg and AHOHNMYC,
|
||||
German translation by Jerry Polfer, Italian translation by
|
||||
Massimiliano Augello and Swedish translation by PLJ / Kosovoper,
|
||||
general fixes contributed by Daniel Dias Rodrigues.
|
||||
|
||||
Testing, reviews and documentation contributed by Dreamer, Vlax,
|
||||
Shining the Translucent, Mancausoft, Asbesto Molesto, Nignux, TheJH,
|
||||
The Grugq, Reiven, GDrooid, Alphazo, Brian May, fsLeg, JoelMon,
|
||||
Narrat, Jerry Polfer, Jim Turner, Maxime Arthaud, RobertMX,
|
||||
mhogomchungu Mandeep Bhutani, Emil Lundberg, Joel Montes de Oca, Armin
|
||||
Mesbah, Arusekk, Stephan Schindel, Asbjørn Apeland, Victor Calvert,
|
||||
bjonnh, SargoDevel, AitorATuin, Alexis Danizan and... the Linux
|
||||
Action Show!
|
||||
The Grugq, Reiven, GDrooid, Alphazo, Brian May, fsLeg, Narrat, Jerry
|
||||
Polfer, Jim Turner, Maxime Arthaud, RobertMX, mhogomchungu Mandeep
|
||||
Bhutani, Emil Lundberg, Joel Montes de Oca, Armin Mesbah, Arusekk,
|
||||
Stephan Schindel, Asbjørn Apeland, Victor Calvert, bjonnh, SargoDevel,
|
||||
AitorATuin, Alexis Danizan, Sven Geuer, Greg Tczap, Aaron Janse, Mark
|
||||
Mykkanen, Alexis Danizan, Steve Litt, James R, Matthieu Crapet, Selene
|
||||
ToyKeeper, Valentin Heidelberg and... the Linux Action Show!
|
||||
|
||||
Tomb includes an implementation of the "Password-Based Key Derivation
|
||||
Function v2" based on GCrypt and written by Anthony Thyssen, with
|
||||
fixes contributed by AitorATuin.
|
||||
|
||||
Tomb developers can be contacted via GitHub issues on
|
||||
https://www.github.com/dyne/Tomb or over IRC https://irc.dyne.org
|
||||
channel **#dyne** (or directly over port 9999 with SSL)
|
||||
Some of the Tomb developers can be contacted via [GitHub discussions](https://github.com/dyne/Tomb/discussions)
|
||||
or over Telegram via the [Dyne.org Chat Channel](https://t.me/dyne_chat).
|
||||
|
73
ChangeLog.md
73
ChangeLog.md
@ -1,5 +1,78 @@
|
||||
# Tomb ChangeLog
|
||||
|
||||
## 2.11
|
||||
### July 2024
|
||||
|
||||
Search engine is upgraded to use recoll, based on xapian backend:
|
||||
offers a GUI and is more up to date, replaces swish-e. Various fixes
|
||||
include a better default of 3 rounds for Argon2 KDF, improved support
|
||||
for cloakify which is now shipped in tomb/extras, new support for
|
||||
pinentry-tty useful for some headless systems and terminals over
|
||||
serial port, improved usage on machines without sudo and support
|
||||
bind-hooks on folders containing spaces in their names. Also the
|
||||
translations to some other languages were improved. All documentation
|
||||
was revisited and reorganized, manpage corrected in some parts and a
|
||||
new homepage is up at https://dyne.org/tomb
|
||||
|
||||
## 2.10
|
||||
### Sep 2023
|
||||
|
||||
This release adds optional support for Argon2 KDF brute-force
|
||||
protection and introduces support for doas as an alternative to sudo
|
||||
for privilege escalation. It also improves support for BTRFS formatted
|
||||
Tombs, adds zram detection as swap memory, updates documentation and
|
||||
translations and cleans up the script code.
|
||||
|
||||
## 2.9
|
||||
### Jan 2021
|
||||
|
||||
This release fixes all bugs introduced by the unfortunate 2.8 release
|
||||
series in 2020 as well introduces support for BTRFS formatted
|
||||
Tombs. The fixes are for password insertion to work on all desktops,
|
||||
as well the fix to a regression when using old Zsh versions. The new
|
||||
feature is activated by the '--filesystem' flag on 'lock' commands.
|
||||
It only supports BTRFS as internal filesystem of a Tomb instead of the
|
||||
default EXT4; resizing works as well to create and send or receive
|
||||
subvolumes and snapshots inside a Tomb. There are also some cleanups,
|
||||
small error handling improvements and no more need for suid actions by
|
||||
'forge' and 'dig' commands.
|
||||
|
||||
|
||||
|
||||
## 2.8.1
|
||||
### Nov 2020
|
||||
|
||||
This is a minor bugfix release. It fixes two bugs introduced by the
|
||||
previous release: the release of loopback devices and a typo affecting
|
||||
password insertion in text-only mode. It also provides a cosmetic fix
|
||||
for the output of 'tomb list' that now displays correct sizes. At
|
||||
last, the docker wrapper has been included in extras/ to be shipped in
|
||||
Tomb. The span of CVE-2020-28638 has been assessed with more precision
|
||||
and KNOWN_BUGS updated accordingly.
|
||||
|
||||
## 2.8
|
||||
### Nov 2020
|
||||
|
||||
This new release updates the documentation, improves usability and
|
||||
fixes two bugs. A bug has been found (CVE-2020-28638) to corrupt
|
||||
passwords entered using pinentry-curses on desktops using a X11
|
||||
DISPLAY, the documentation in KNOWN_BUGS outlines how to fix
|
||||
regressions. Another bug has been fixed to prevent mounting tombs that
|
||||
are already opened, a situation leading to potential data loss.
|
||||
Changes mentioned lead to a small internal refactoring and cleanup,
|
||||
leading to a change in the way volumes appear in /dev/mapper. Along
|
||||
the usability improvements are the support of GNUPGHOME environment
|
||||
variable to support non-standard GnuPG home locations as well updated
|
||||
translations and the fact that debug messages are now written to
|
||||
stderr, making it easier to parse stdout.
|
||||
|
||||
## 2.7
|
||||
### Oct 2019
|
||||
|
||||
Fixed getent parsing of passwd and notation of conditionals
|
||||
normalised. A few other minor fixes and documentation improvements.
|
||||
|
||||
|
||||
## 2.6
|
||||
### May 2019
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
Tomb needs a few programs to be installed on a system in order to work:
|
||||
|
||||
* zsh
|
||||
* file
|
||||
* sudo
|
||||
* gnupg
|
||||
* cryptsetup
|
||||
@ -50,7 +51,7 @@ The key can also be hidden in an image, to be used as key later
|
||||
tomb bury -k secrets.tomb.key nosferatu.jpg (hide the key in a jpeg image)
|
||||
tomb open -k nosferatu.jpg secrets.tomb (use the jpeg image to open the tomb)
|
||||
|
||||
Or backupped to a QRCode that can be printed on paper and hidden in
|
||||
Or backed up to a QRCode that can be printed on paper and hidden in
|
||||
books. QRCodes can be scanned with any mobile application, resulting
|
||||
into a block of text that can be used with `-k` just as a normal key.
|
||||
|
||||
@ -71,8 +72,8 @@ executable | function
|
||||
steghide | bury and exhume keys inside images
|
||||
resizefs | extend the size of existing tomb volumes
|
||||
qrencode | engrave keys into printable qrcode sheets
|
||||
mlocate | fast search of file names inside tombs
|
||||
swish++ | fast search of file contents inside tombs
|
||||
plocate | fast search of file names inside tombs
|
||||
recoll | fast search of file contents inside tombs
|
||||
unoconv | fast search of contents in PDF and DOC files
|
||||
lesspipe | fast search of contents in compressed archives
|
||||
haveged | fast entropy generation for key forging
|
||||
@ -102,7 +103,7 @@ To have it change directory `extras/gtk-tray` then
|
||||
3. run `sudo make install` (default PREFIX is `/usr/local`)
|
||||
4. start `tomb-gtk-tray tombname` after the tomb is open
|
||||
|
||||
Of cource one can include the launch of tomb-gtk-tray scripts.
|
||||
Of course, one can include the launch of tomb-gtk-tray scripts.
|
||||
|
||||
## extras/qt-tray
|
||||
|
||||
|
@ -1,3 +1,16 @@
|
||||
# Password bug in X11 when using pinentry-curses
|
||||
## Issue with Tomb version 2.6 and 2.7
|
||||
|
||||
This bug affects systems with a running X11 DISPLAY, but where only
|
||||
pinentry-ncurses is installed. It wrongly reads the input password: no
|
||||
matter what string is chosen, the password becomes:
|
||||
|
||||
tomb [W] Detected DISPLAY, but only pinentry-curses is found.
|
||||
|
||||
Following the fix in Tomb 2.8 affected users will need to use the line
|
||||
above as password to open their tomb and should change their key with
|
||||
a new password using 'tomb passwd'.
|
||||
|
||||
# Cryptsetup change of default to luks2
|
||||
## Issue opening tombs with cryptsetup >2.0
|
||||
|
||||
@ -9,16 +22,16 @@ cryptsetup v2.1 a new default has been introduced (luks2) and the
|
||||
Using Tomb version 2.6 (and future releases) the problem opening tombs
|
||||
using recent GNU/Linux distributions is fixed.
|
||||
|
||||
# Whitespaces in KDF passwords
|
||||
# Whitespace in KDF passwords
|
||||
## Issue affecting passwords used with PBKDF2 keys (<2.6)
|
||||
|
||||
Up until and including Tomb's version 2.5 the PBKDF2 wrapper for keys
|
||||
in Tomb has a bug affecting passwords that contain whitespaces. Since
|
||||
in Tomb has a bug affecting passwords that contain whitespace. Since
|
||||
the passwords are trimmed at the first whitespace, this makes them
|
||||
weaker, while fortunately the KDF transformation still applies.
|
||||
|
||||
This issue is fixed in Tomb version 2.6: all users adopting KDF keys
|
||||
that have passwords containing whitespaces should change them,
|
||||
that have passwords containing whitespace should change them,
|
||||
knowing that their "old password" is trimmed until the whitespace.
|
||||
|
||||
Users adopting GPG keys or plain (without KDF wrapper) can ignore
|
||||
|
10
Makefile
10
Makefile
@ -2,6 +2,14 @@ PROG = tomb
|
||||
PREFIX ?= /usr/local
|
||||
MANDIR ?= ${PREFIX}/share/man
|
||||
|
||||
deps:
|
||||
@if [ -r /etc/debian_version ]; then \
|
||||
apt-get install -qy zsh cryptsetup file gnupg pinentry-curses; fi
|
||||
@if [ -r /etc/fedora-release ]; then \
|
||||
yum install -y zsh cryptsetup file gnupg pinentry-curses; fi
|
||||
@if [ -r /etc/alpine-release ]; then \
|
||||
apk add zsh cryptsetup file gpg pinentry-tty e2fsprogs findmnt; fi
|
||||
|
||||
all:
|
||||
@echo
|
||||
@echo "Tomb is a script and does not need compilation, it can be simply executed."
|
||||
@ -26,4 +34,4 @@ test:
|
||||
make -C extras/test
|
||||
|
||||
lint:
|
||||
shellcheck -s zsh -e SC1073,SC1027,SC1072,SC1083,SC1009 tomb
|
||||
shellcheck -s bash -e SC1058,SC1073,SC1072,SC1009 tomb
|
||||
|
304
README.md
304
README.md
@ -1,308 +1,58 @@
|
||||
..... ..
|
||||
.H8888888h. ~-. . uW8"
|
||||
888888888888x `> u. .. . : `t888
|
||||
X~ `?888888hx~ ...ue888b .888: x888 x888. 8888 .
|
||||
' x8.^"*88*" 888R Y888r ~`8888~'888X`?888f` 9888.z88N
|
||||
`-:- X8888x 888R I888> X888 888X '888> 9888 888E
|
||||
488888> 888R I888> X888 888X '888> 9888 888E
|
||||
.. `"88* 888R I888> X888 888X '888> 9888 888E
|
||||
x88888nX" . u8888cJ888 X888 888X '888> 9888 888E
|
||||
!"*8888888n.. : "*888*P" "*88%""*88" '888!` .8888 888"
|
||||
' "*88888888* 'Y" `~ " `"` `%888*%"
|
||||
^"***"` "`
|
||||
# Tomb: The Linux Crypto Undertaker
|
||||
|
||||
*A minimalistic commandline tool to manage encrypted volumes* aka **The Crypto Undertaker**
|
||||
[![Build Status](https://github.com/dyne/tomb/actions/workflows/linux.yml/badge.svg)](https://github.com/dyne/Tomb/actions)
|
||||
<!-- [![Build Status](https://github.com/dyne/tomb/actions/workflows/portable.yml/badge.svg)](https://github.com/dyne/Tomb/actions) -->
|
||||
|
||||
[![software by Dyne.org](https://files.dyne.org/software_by_dyne.png)](http://www.dyne.org)
|
||||
Minimalistic command line tool based on Linux dm-crypt and LUKS, trusted by hackers since 2007.
|
||||
|
||||
More information and updates on website: https://www.dyne.org/software/tomb
|
||||
|
||||
Get the stable .tar.gz signed release for production use!
|
||||
|
||||
Download it from https://files.dyne.org/tomb
|
||||
|
||||
For the instructions on how to get started using Tomb, see [INSTALL](INSTALL.md).
|
||||
You can keep your volumes secure and easily manageable with simple commands.
|
||||
|
||||
![tomb's logo](https://github.com/dyne/Tomb/blob/master/extras/images/monmort.png)
|
||||
|
||||
[![Build Status](https://travis-ci.org/dyne/Tomb.svg?branch=master)](https://travis-ci.org/dyne/Tomb)
|
||||
|
||||
# What is Tomb, the crypto undertaker?
|
||||
|
||||
Tomb aims to be a free and open source system for easy encryption and
|
||||
backup of personal files, written in code that is easy to review and
|
||||
links well reliable GNU/Linux components.
|
||||
|
||||
Tomb's ambition is to improve safety by way of:
|
||||
|
||||
- a minimalist design consisting in small and well readable code
|
||||
- facilitation of good practices, i.e: key/storage physical separation
|
||||
- adoption of a few standard and well tested implementations.
|
||||
|
||||
At present, Tomb consists of a simple shell script (Zsh) using
|
||||
standard filesystem tools (GNU) and the cryptographic API of the Linux
|
||||
kernel (cryptsetup and LUKS). Tomb can also produce machine parsable
|
||||
output to facilitate its use inside graphical applications.
|
||||
|
||||
# How does it work?
|
||||
|
||||
To create a Tomb, do:
|
||||
Create a new 120MiB `secret.tomb` folder and lock it with a new `secret.tomb.key` file.
|
||||
```
|
||||
$ tomb dig -s 100 secret.tomb
|
||||
$ tomb forge secret.tomb.key
|
||||
$ tomb lock secret.tomb -k secret.tomb.key
|
||||
$ tomb dig -s 120 secret.tomb
|
||||
$ tomb forge -k secret.tomb.key
|
||||
$ tomb lock -k secret.tomb.key secret.tomb
|
||||
```
|
||||
To open it, do
|
||||
```
|
||||
$ tomb open secret.tomb -k secret.tomb.key
|
||||
$ tomb open -k secret.tomb.key secret.tomb
|
||||
```
|
||||
and after you are done
|
||||
And after you are done
|
||||
```
|
||||
$ tomb close
|
||||
```
|
||||
or if you are in a hurry
|
||||
Or, if you are in a hurry, kill all processes with open files inside your tomb and close it.
|
||||
```
|
||||
$ tomb slam all
|
||||
$ tomb slam
|
||||
```
|
||||
## 📖 [Get started on dyne.org/tomb](https://dyne.org/tomb)
|
||||
|
||||
```
|
||||
Syntax: tomb [options] command [arguments]
|
||||
<a href="https://dyne.org/tomb"><img src="https://files.dyne.org/software_by_dyne.png" width="30%"></a>
|
||||
|
||||
Commands:
|
||||
More information in `man tomb` and on [dyne.org/docs/tomb](https://dyne.org/docs/tomb).
|
||||
|
||||
// Creation:
|
||||
dig create a new empty TOMB file of size -s in MiB
|
||||
forge create a new KEY file and set its password
|
||||
lock installs a lock on a TOMB to use it with KEY
|
||||
### 💾 [Download from files.dyne.org/tomb](https://files.dyne.org/tomb/)
|
||||
|
||||
// Operations on tombs:
|
||||
open open an existing TOMB (-k KEY file or - for stdin)
|
||||
index update the search indexes of tombs
|
||||
search looks for filenames matching text patterns
|
||||
list list of open TOMBs and information on them
|
||||
ps list of running processes inside open TOMBs
|
||||
close close a specific TOMB (or 'all')
|
||||
slam slam a TOMB killing all programs using it
|
||||
resize resize a TOMB to a new size -s (can only grow)
|
||||
Use only stable and signed releases in production!
|
||||
|
||||
// Operations on keys:
|
||||
passwd change the password of a KEY (needs old pass)
|
||||
setkey change the KEY locking a TOMB (needs old key and pass)
|
||||
Tomb's development is community-based!
|
||||
|
||||
// Backup on paper:
|
||||
engrave makes a QR code of a KEY to be saved on paper
|
||||
## 🤏🏽 How can you help
|
||||
|
||||
// Steganography:
|
||||
bury hide a KEY inside a JPEG image (for use with -k)
|
||||
exhume extract a KEY from a JPEG image (prints to stdout)
|
||||
cloak transform a KEY into a TEXT using CIPHER (for use with -k)
|
||||
uncloak extract a KEY from a TEXT file using CIPHER (prints to stdout)
|
||||
Donations are very welcome on [dyne.org/donate](https://www.dyne.org/donate)
|
||||
|
||||
Options:
|
||||
Translations are also welcome: see our simple [translation guide](https://github.com/dyne/Tomb/blob/master/extras/translations/README.md)
|
||||
|
||||
-s size of the tomb file when creating/resizing one (in MiB)
|
||||
-k path to the key to be used ('-k -' to read from stdin)
|
||||
-n don't process the hooks found in tomb
|
||||
-o options passed to commands: open, lock, forge (see man)
|
||||
-f force operation (i.e. open even if swap is active)
|
||||
-g use a GnuPG key to encrypt a tomb key
|
||||
-r provide GnuPG recipients (separated by comma)
|
||||
-R provide GnuPG hidden recipients (separated by comma)
|
||||
--kdf forge keys armored against dictionary attacks
|
||||
Tomb's code is short and readable: don't be afraid to inspect it! If you plan to submit a PR, please remember that this is a minimalist tool, and the code should be short and readable. Also, first, read our small intro to [Tomb's coding style](doc/HACKING.txt).
|
||||
|
||||
-h print this help
|
||||
-v print version, license and list of available ciphers
|
||||
-q run quietly without printing informations
|
||||
-D print debugging information at runtime
|
||||
```
|
||||
We have a [space for issues](https://github.com/dyne/Tomb/issues) open for detailed bug reports. Always include the Tomb version being used when filing a case, please.
|
||||
|
||||
# What is this for, exactly?
|
||||
|
||||
This tool can be used to dig .tomb files (LUKS volumes), forge keys
|
||||
protected by a password (GnuPG encryption) and use the keys to lock
|
||||
the tombs. Tombs are like single files whose contents are inaccessible
|
||||
in the absence of the key they were locked with and its password.
|
||||
|
||||
Once open, the tombs are just like normal folders and can contain
|
||||
different files, plus they offer advanced functionalities like bind
|
||||
and execution hooks and fast search, or they can be slammed close even
|
||||
if busy. Keys can be stored on separate media like USB sticks, NFC,
|
||||
on-line SSH servers or bluetooth devices to make the transport of data
|
||||
safer: one always needs both the tomb and the key, plus its password,
|
||||
to access it.
|
||||
|
||||
The tomb script takes care of several details to improve user's
|
||||
behaviour and the security of tombs in everyday usage: protects the
|
||||
typing of passwords from keyloggers, facilitates hiding keys inside
|
||||
images, indexes and search a tomb's contents, mounts directories in
|
||||
place, lists open tombs and selectively closes them, warns the user
|
||||
about free space and last time usage, etc.
|
||||
|
||||
# How secure is this?
|
||||
|
||||
Death is the only sure thing in life. That said, Tomb is a pretty
|
||||
secure tool especially because it is kept minimal, its source is
|
||||
always open to review (even when installed) and its code is easy to
|
||||
read with a bit of shell script knowledge.
|
||||
|
||||
All encryption tools being used in Tomb are included as default in
|
||||
many GNU/Linux operating systems and therefore are regularly peer
|
||||
reviewed: we don't add anything else to them really, just a layer of
|
||||
usability.
|
||||
|
||||
The file [KNOWN_BUGS.md](KNOWN_BUGS.md) contains some notes on known
|
||||
vulnerabilities and threat model analysis.
|
||||
|
||||
In absence or malfunction of the Tomb script it is always possible to
|
||||
access the contents of a Tomb only using a dm-crypt enabled Linux
|
||||
kernel, cryptsetup, GnuPG and any shell interpreter issuing the
|
||||
following commands as root:
|
||||
```
|
||||
lo=$(losetup -f)
|
||||
losetup -f secret.tomb
|
||||
pass="$(gpg -d secret.key)"
|
||||
echo -n -e "$pass" | cryptsetup --key-file - luksOpen $lo secret
|
||||
mount /dev/mapper/secret /mnt
|
||||
unset pass
|
||||
```
|
||||
One can change the last argument `/mnt` to where the Tomb has to be
|
||||
mounted and made accessible. To close the tomb then use:
|
||||
```
|
||||
umount /mnt
|
||||
cryptsetup luksClose /dev/mapper/secret
|
||||
```
|
||||
|
||||
# Stage of development
|
||||
|
||||
Tomb is an evolution of the 'mknest' tool developed for the
|
||||
[dyne:bolic](http://www.dynebolic.org) 100% Free GNU/Linux
|
||||
distribution in 2001: its 'nesting' mechanism allowed the liveCD users
|
||||
to encrypt and make persistent home directories. Since then the same
|
||||
shell routines kept being maintained and used for dyne:bolic until
|
||||
2007, when they were ported to work on more GNU/Linux distributions.
|
||||
|
||||
As of today, Tomb is a very stable tool also used in mission critical
|
||||
situations by a number of activists in dangerous zones. It has been
|
||||
reviewed by forensics analysts and it can be considered safe for
|
||||
adoption where the integrity of information stored depends on the
|
||||
user's behaviour and the strength of a standard AES-256 (XTS plain)
|
||||
encryption algorithm (current default) or, at one's option, other
|
||||
equivalent standards supported by the Linux kernel.
|
||||
|
||||
## Compatibility
|
||||
|
||||
Tomb can be used in conjunction with some other software applications,
|
||||
some are developed by Dyne.org, but some also by third parties.
|
||||
|
||||
### Included extra applications
|
||||
|
||||
These auxiliary applications are found in the extras/ subdirectory of
|
||||
distributed Tomb's sourcecode:
|
||||
|
||||
- [GTomb](extras/gtomb) is a graphical interface using zenity
|
||||
- [gtk-tray](extras/gtk-tray) is a graphical tray icon for GTK panels
|
||||
- [qt-tray](extras/qt-tray) is a graphical tray icon for QT panels
|
||||
- [tomber](extras/tomber) is a wrapper to use Tomb in Python scripts
|
||||
|
||||
![skulls and pythons](https://github.com/dyne/Tomb/blob/master/extras/images/python_for_tomb.png)
|
||||
|
||||
### External applications
|
||||
|
||||
The following applications are not included in Tomb's distributed
|
||||
sourcecode, but are known and tested to be compatible with Tomb:
|
||||
|
||||
- [Secrets](https://secrets.dyne.org) is a software that can be operated on-line and on-site to split a Tomb key in shares to be distributed to peers: some of them have to agree to combine back the shares in order to retrieve the key.
|
||||
|
||||
- [zuluCrypt](https://mhogomchungu.github.io/zuluCrypt/) is a graphical application to manage various types of encrypted volumes on GNU/Linux, among them also Tombs, written in C++.
|
||||
|
||||
- [Mausoleum](https://github.com/mandeep/Mausoleum) is a graphical interface to facilitate the creation and management of tombs, written in Python.
|
||||
|
||||
|
||||
- [pass-tomb](https://github.com/roddhjav/pass-tomb) is a console based wrapper of the excellent password keeping program [pass](https://www.passwordstore.org) that helps to keep the whole tree of password encrypted inside a tomb. It is written in Bash.
|
||||
|
||||
If you are writing a project supporting Tomb volumes or wrapping Tomb, let us know!
|
||||
|
||||
|
||||
## Compliancy
|
||||
|
||||
Tomb qualifies as sound for use on information rated as "top secret"
|
||||
when used on an underlying stack of carefully reviewed hardware
|
||||
(random number generator and other components) and software (Linux
|
||||
kernel build, crypto modules, device manager, compiler used to built,
|
||||
shell interpreter and packaged dependencies).
|
||||
|
||||
Tomb volumes are fully compliant with the FIPS 197 advanced encryption
|
||||
standard published by NIST and with the following industry standards:
|
||||
|
||||
- Information technology -- Security techniques -- Encryption algorithms
|
||||
- [ISO/IEC 18033-1:2015](http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=54530) -- Part 1: General
|
||||
- [ISO/IEC 18033-3:2010](http://www.iso.org/iso/home/store/catalogue_ics/catalogue_detail_ics.htm?csnumber=54531) -- Part 3: Block ciphers
|
||||
|
||||
Tomb implementation is known to address at least partially issues raised in:
|
||||
|
||||
- Information technology -- Security techniques -- Key management
|
||||
- [ISO/IEC 11770-1:2010](http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=53456) -- Part 1: Framework
|
||||
- [ISO/IEC 11770-2:2008](http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=46370) -- Part 2: Mechanisms using symmetric techniques
|
||||
- [ISO/IEC 27005:2011](http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=56742) Information technology -- Security techniques -- Information security risk management
|
||||
- [ISO/IEC 24759:2014](http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=59142) Information technology -- Security techniques -- Test requirements for cryptographic modules
|
||||
|
||||
Any help on further verification of compliancy is very welcome, as the
|
||||
access to ISO/IEC document is limited due to its expensive nature.
|
||||
|
||||
|
||||
# Use stable releases in production!
|
||||
|
||||
Anyone planning to use Tomb to store and access secrets should not use
|
||||
the latest development version in Git, but use instead the .tar.gz
|
||||
release on https://files.dyne.org/tomb . The stable version will
|
||||
always ensure backward compatibility with older tombs: we make sure it
|
||||
creates sane tombs and keys by running various tests before releasing
|
||||
it. The development version in Git might introduce sudden bugs and is
|
||||
not guaranteed to produce backward- or forward-compatible tombs and keys.
|
||||
The development version in Git should be used to report bugs, test new
|
||||
features and develop patches.
|
||||
|
||||
So be warned: do not use the latest Git version in production
|
||||
environments, but use a stable release versioned and packed as
|
||||
tarball on https://files.dyne.org/tomb
|
||||
|
||||
![Day of the dead](https://github.com/dyne/Tomb/blob/master/extras/images/DayOfTheDead.jpg)
|
||||
|
||||
# How can you help
|
||||
|
||||
Donations are very welcome, please go to https://www.dyne.org/donate
|
||||
|
||||
Translations are also welcome: they can be contributed editing sending
|
||||
the .po files in [extras/translations](extras/translations).
|
||||
|
||||
The code is pretty short and readable. There is also a collection of
|
||||
specifications and design materials in the [doc](doc) directory.
|
||||
|
||||
To contribute code and reviews visit https://github.com/dyne/Tomb
|
||||
|
||||
If you plan to commit code into Tomb, please keep in mind this is a
|
||||
minimalist tool and its code should be readable. Guidelines on the
|
||||
coding style are illustrated in [doc/HACKING.txt](doc/HACKING.txt).
|
||||
|
||||
Tomb's developers can be contacted using the issues on GitHub or over
|
||||
IRC on https://irc.dyne.org channel **#dyne** (or direct port 9999 SSL)
|
||||
There is also a [space for discussion](https://github.com/dyne/Tomb/discussions) of new features, desiderata and whatnot on github.
|
||||
|
||||
# Licensing
|
||||
|
||||
Tomb is Copyright (C) 2007-2019 by the Dyne.org Foundation and
|
||||
maintained by Denis Roio <jaromil@dyne.org>. More information on all
|
||||
the developers involved is found in the [AUTHORS](AUTHORS.md) file.
|
||||
Tomb is Copyright (C) 2007-2024 by the Dyne.org Foundation and maintained by [Jaromil](https://github.com/jaromil). The [AUTHORS](AUTHORS.md) file contains more information on all the developers involved. The license is GNU Public License v3.
|
||||
|
||||
This source code is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This source code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Please refer
|
||||
to the GNU Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Public License along with
|
||||
this source code; if not, write to: Free Software Foundation, Inc.,
|
||||
675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
## [More info on dyne.org/tomb](https://dyne.org/tomb)
|
||||
|
@ -1,13 +1,11 @@
|
||||
Overview
|
||||
=========
|
||||
|
||||
|
||||
What's a key?
|
||||
It basicly is a gpg simmetrically encrypted, ascii-armored file.
|
||||
It's encryption key is a function (see below, on KDF section) of your tomb
|
||||
What is a key?
|
||||
It is a gpg symmetrically encrypted, ascii-armored file.
|
||||
The encryption key is a function (see below, on KDF section) of your tomb
|
||||
passphrase.
|
||||
|
||||
|
||||
Layout
|
||||
======
|
||||
|
||||
|
@ -31,11 +31,11 @@ Linux hard disk encryption settings
|
||||
and LRW for standardisation. EME along with it's cousin CMC seems to
|
||||
provide the best security level, but imposes additional encryption
|
||||
steps. Plumb-IV is discussed only for reference, because it has the
|
||||
same performance penalty as CMC, but in constrast suffers from
|
||||
same performance penalty as CMC, but in contrast suffers from
|
||||
weaknesses of CBC encryption.
|
||||
|
||||
As convention, this document will use the term "blocks", when it
|
||||
referes to a single block of plain or cipher text (usually 16 byte),
|
||||
refers to a single block of plain or cipher text (usually 16 byte),
|
||||
and will use the term "sectors", when it refers to a 512-byte wide hard
|
||||
disk block.
|
||||
|
||||
@ -171,8 +171,8 @@ Content leaks
|
||||
cipher blocks. But how does this number grow in n? Obviously
|
||||
exponentially. Plotting a few a decimal powers shows that the chance
|
||||
for finding at least on identical cipher pair flips to 1 around n =
|
||||
10^20 (n = 10^40 for a 256-bit cipher). This inflexion point is reached
|
||||
for a 146 million TB storage (or a hundered thousand trillion trillions
|
||||
10^20 (n = 10^40 for a 256-bit cipher). This inflection point is reached
|
||||
for a 146 million TB storage (or a hundred thousand trillion trillions
|
||||
TB storage for a 256-bit cipher).
|
||||
|
||||
^1The blocks with available preceding cipher blocks is 62/1KB for all
|
||||
|
206
doc/tomb.1
206
doc/tomb.1
@ -1,4 +1,4 @@
|
||||
.TH tomb 1 "May 22, 2019" "tomb"
|
||||
.TH tomb 1 "Jun 25, 2023" "tomb"
|
||||
|
||||
.SH NAME
|
||||
Tomb \- the Crypto Undertaker
|
||||
@ -32,23 +32,24 @@ Generates a file that can be used as a tomb and will occupy as much
|
||||
space as its desired initial size, the unlocked \fI.tomb\fR file can
|
||||
then be locked using a \fIkey\fR. It takes a mandatory \fI-s\fR option
|
||||
which is the size in megabytes (MiB). Tombs are digged using random
|
||||
data gathered from a non-blocking source (/dev/urandom).
|
||||
data gathered from a non-blocking source (/dev/urandom). For very
|
||||
large tombs this may take up too much time and entropy, then it is
|
||||
possible to use \fIfallocate(1)\fR being aware it does not pre-fill
|
||||
with random data, decreasing the tomb's security.
|
||||
|
||||
.B
|
||||
.IP "forge"
|
||||
Creates a new \fIkey\fR and prompts the user for a \fIpassword\fR to
|
||||
protect its usage using symmetric encryption. This operation uses
|
||||
random data from a non-blocking source (/dev/urandom) and it may take
|
||||
long only in some cases; to switch using a blocking source the
|
||||
\fI--use-random\fR flag can be used. The \fI-g\fR option switches on
|
||||
the use of a GPG key instead of a password (asymmetric encryption),
|
||||
then the \fI-r\fR option indicates the recipient key; more recipient
|
||||
GPG ids can be indicated (comma separated). The default cipher to
|
||||
protect the key is AES256, a custom one can be specified using the
|
||||
\fI-o\fR option, for a list of supported ciphers use \fI-v\fR. For
|
||||
additional protection against dictionary attacks on keys, the
|
||||
\fI--kdf\fR option can be used when forging a key, making sure that
|
||||
the \fItomb-kdb-pbkdf2\fR binaries in \fIextras/kdf\fR were compiled
|
||||
Creates a new \fIkey\fR and prompts the user for a \fIpassword\fR to protect
|
||||
its usage using symmetric encryption. This operation uses random data from a
|
||||
non-blocking source (/dev/urandom) and it may take long only in some cases; to
|
||||
switch using a blocking source the \fI--use-random\fR flag can be used. The
|
||||
\fI-g\fR option switches on the use of a GPG key instead of a password
|
||||
(asymmetric encryption), then the \fI-r\fR option indicates the recipient key;
|
||||
more recipient GPG ids can be indicated (comma separated). The default cipher
|
||||
to protect the key is AES256, a custom one can be specified using the \fI-o\fR
|
||||
option, for a list of supported ciphers use \fI-v\fR. For additional protection
|
||||
against dictionary attacks on keys, the \fI--kdf\fR option can be used when
|
||||
forging a key, making sure that the binaries in \fIextras/kdf\fR were compiled
|
||||
and installed on the system.
|
||||
|
||||
.B
|
||||
@ -61,12 +62,32 @@ option \fI-k\fR should be used to specify a key file; in case of
|
||||
encryption to GPG recipients the \fI-g\fR flag should be used followed
|
||||
by \fI-r\fR and the recipient's secret GPG key id. The \fI-o\fR
|
||||
option can be used to specify the cipher specification: default is
|
||||
"aes-xts-plain64:sha256", old versions of Tomb used
|
||||
"aes-cbc-essiv:sha256". If you are looking for something exotic, also
|
||||
try "serpent-xts-plain64". More options may be found in cryptsetup(8)
|
||||
and Linux documentation. This operation requires root privileges to
|
||||
loopback mount, format the tomb (using LUKS and Ext4), then set the
|
||||
key in its first LUKS slot.
|
||||
"aes-xts-plain64", old versions of Tomb used "aes-cbc-essiv:sha256".
|
||||
If you are looking for something exotic, also try
|
||||
"serpent-xts-plain64". More options may be found in cryptsetup(8) and
|
||||
Linux documentation. The \fI--filesystem\fR option can be used to
|
||||
specify an alternative filesystem used to format the tomb,
|
||||
in place of the default "ext4". This operation requires root
|
||||
privileges to loopback mount, format the tomb (using LUKS and mkfs),
|
||||
then set the key in its first LUKS slot.
|
||||
|
||||
.RS
|
||||
Supported filesystems for \fI--filesystem\fR:
|
||||
.PD 0
|
||||
.IP "ext3" 15
|
||||
using operating system defaults
|
||||
.IP "ext4"
|
||||
using operating system defaults
|
||||
.IP "btrfs"
|
||||
for tombs >= 47MB using operating system defaults
|
||||
.IP "btrfsmixedmode"
|
||||
for tombs >=18MB btrfs mixed mode (see mkfs.btrfs(8))
|
||||
.IP "ext3maxinodes"
|
||||
ext3 with a maximum of inodes (for many small files)
|
||||
.IP "ext4maxinodes"
|
||||
ext4 with a maximum of inodes (for many small files)
|
||||
.PD
|
||||
.RE
|
||||
|
||||
.B
|
||||
.IP "open"
|
||||
@ -101,19 +122,21 @@ internally to enumerate processes running in one or all tombs.
|
||||
.IP "index"
|
||||
Creates or updates the search indexes of all tombs currently open:
|
||||
enables use of the \fIsearch\fR command using simple word patterns on
|
||||
file names. Indexes are created using mlocate's updatedb(8) and
|
||||
swish-e(1) if they are found on the system. Indexes allow to search
|
||||
file names. Indexes are created using plocate's updatedb(8) and
|
||||
recoll(1) if they are found on the system. Indexes allow one to search
|
||||
very fast for filenames and contents inside a tomb, they are stored
|
||||
inside it and are not accessible if the Tomb is closed. To avoid
|
||||
indexing a specific tomb simply touch a \fI.noindex\fR file in it.
|
||||
Useful tools to have: poppler-utils, aspell, xdg-utils, plocate.
|
||||
|
||||
.B
|
||||
.IP "search"
|
||||
Takes any string as argument and searches for them through all tombs
|
||||
currently open and previously indexed using the \fIindex\fR command.
|
||||
The search matches filenames if mlocate is installed and then also
|
||||
file contents if swish++ is present on the system, results are listed
|
||||
on the console.
|
||||
The search matches filenames if plocate is installed and then also
|
||||
file contents if recoll is installed, all results are listed on the
|
||||
console.
|
||||
One can also run recoll's GUI using \fIrecoll -c /media/tomb\fR
|
||||
|
||||
.B
|
||||
.IP "close"
|
||||
@ -196,22 +219,19 @@ key is buried in any image or not.
|
||||
|
||||
.B
|
||||
.IP "cloak"
|
||||
Hides a tomb key (\fI-k\fR) inside a \fIlong plain-text file\fR (first
|
||||
argument) using \fIsteganography\fR: the text will change in a way
|
||||
that can hardly be noticed by human eye and hardly detected by data
|
||||
analysis. This option is useful to backup tomb keys in unsuspected
|
||||
places; it depends from the availability of \fIcloakify\fR and
|
||||
consequently \fIpython2\fR. This function does not support asymmetric
|
||||
encryption using the \fI-g\fR flag.
|
||||
Cloaks a tomb key (\fI-k\fR) disguising it as a text file using a
|
||||
cipher from \fIextras/cloak/ciphers\fR (second argument) using
|
||||
\fIcloakify\fR. This option is useful to backup tomb keys in
|
||||
unsuspected places; it needs \fIextras/cloak\fR installed and
|
||||
\fIpython3\fR.
|
||||
|
||||
.B
|
||||
.IP "uncloak"
|
||||
This command recovers from long plain-text files the keys that were
|
||||
previously hidden into them using \fIcloak\fR. Cloak requires a key
|
||||
filename (\fI-k\fR) and a \fIplain-text\fR file (first argument) known
|
||||
to be containing a key. If the right key password is given, the key
|
||||
will be exhumed. If the password is not known, it is quite hard to
|
||||
verify if a key is buried in a text or not.
|
||||
Recovers a tomb key from a cloaked text file. Uncloak requires a text
|
||||
file (first argument), a cipher file (second argument) and optionally
|
||||
an output file (third argument). If the first two parameters are
|
||||
correct then the output will be a valid tomb key file restored from
|
||||
cloak.
|
||||
|
||||
.SH OPTIONS
|
||||
.B
|
||||
@ -225,14 +245,14 @@ commands, or text files retrieved from \fIengraved\fR QR codes. If the
|
||||
stdin (blocking).
|
||||
.B
|
||||
.IP "-n"
|
||||
Skip processing of post-hooks and bind-hooks if found inside the tomb.
|
||||
Skip processing of exec-hooks and bind-hooks if found inside the tomb.
|
||||
See the \fIHOOKS\fR section in this manual for more information.
|
||||
.B
|
||||
.IP "-p"
|
||||
When opening a tomb, preserves the ownership of all files and
|
||||
directories contained in it. Normally the \fIopen\fR command changes
|
||||
the ownership of a tomb's contents to the UID and GID of the user who
|
||||
has succesfully opened it: it is a usability feature in case a tomb is
|
||||
has successfully opened it: it is a usability feature in case a tomb is
|
||||
used by a single user across different systems. This flag deactivates
|
||||
this behaviour.
|
||||
.B
|
||||
@ -242,7 +262,7 @@ of the default \fIrw,noatime,nodev\fR, i.e. to mount a tomb read-only
|
||||
(ro) to prevent any modification of its data. Can also be used to
|
||||
change the symmetric encryption algorithm for keys during \fIforge\fR
|
||||
operations (default \fIAES256\fR) or the LUKS encryption method during
|
||||
\fIlock\fR operations (default \fIaes-xts-plain64:sha256\fR).
|
||||
\fIlock\fR operations (default \fIaes-xts-plain64\fR).
|
||||
.B
|
||||
.IP "-f"
|
||||
Force flag, currently used to override swap checks, might be
|
||||
@ -255,7 +275,8 @@ the \fIsize\fR of the new file to be created. Units are megabytes (MiB).
|
||||
.B
|
||||
.IP "-g"
|
||||
Tell tomb to use a asymmetric GnuPG key encryption instead of a
|
||||
symmetric passphrase to protect a tomb key. This option can be followed by \fI-r\fR when the command needs to specify recipient(s).
|
||||
symmetric passphrase to protect a tomb key. This option can be
|
||||
followed by \fI-r\fR when the command needs to specify recipient(s).
|
||||
.B
|
||||
.IP "-r \fI<gpg_id>[,<gpg_id2>]\fR"
|
||||
Provide a new set of recipient(s) to encrypt a tomb key. \fIgpg_ids\fR
|
||||
@ -263,22 +284,28 @@ can be one or more GPG key ID, comma separated. All GPG keys must be
|
||||
trusted keys in GPG.
|
||||
.B
|
||||
.IP "--kdf \fI<itertime>\fR"
|
||||
Activate the KDF feature against dictionary attacks when creating a
|
||||
key: forces a delay of \fI<itertime>\fR times every time this key is
|
||||
used. The actual time to wait depends on the CPU speed of the
|
||||
computer where the key is used. Using 5 or 10 is a sane amount for
|
||||
modern computers, the value is multiplied by 1 million.
|
||||
Activate the KDF feature against dictionary attacks when creating a key: forces
|
||||
a delay of \fI<itertime>\fR times every time this key is used. The actual time
|
||||
to wait depends on the CPU speed (default) or the RAM size (argon2) of the
|
||||
computer where the key is used. Using 5 or 10 is a sane amount for modern
|
||||
computers, the value is multiplied by 1 million.
|
||||
.B
|
||||
.IP "--sphx-user \fI<username>\fR"
|
||||
Activate the SPHINX feature for password-authenticated key agreement.
|
||||
This option indicates the \fI<username>\fR used to retrieve the
|
||||
password from a sphinx oracle key reachable via TCP/IP.
|
||||
|
||||
.IP "--sphx-host \fI<domain>\fR"
|
||||
Activate the SPHINX feature for password-authenticated key agreement.
|
||||
This option indicates the \fI<domain>\fR used to retrieve the password
|
||||
from a sphinx oracle daemon reachable via TCP/IP. This is not the
|
||||
network address of the daemon, which is configured in /etc/sphinx
|
||||
.IP "--kdftype \fIargon2 | pbkdf2\fR"
|
||||
Adopt the \fIargon2\fR algorithm for KDF, stressing the RAM capacity rather
|
||||
than the CPU speed of the computer decrypting the tomb. Requires the
|
||||
\fIargon2\fR binary by P-H-C to be installed, as packaged by most distros.
|
||||
Default is \fIpbkdf2\fR.
|
||||
.B
|
||||
.IP "--kdfmem \fI<memory>\fR"
|
||||
In case of \fIargon2\fR KDF algorithm, this value specifies the size of RAM
|
||||
used: it consists of a number which is the elevated power of two in kilobytes.
|
||||
Default is 18 which is 250 MiB (2^18 = 262,144 kilobytes).
|
||||
.B
|
||||
.IP "--sudo \fI<executable>\fR"
|
||||
Select a different tool than sudo for privilege escalation.
|
||||
Alternatives supported so far are: pkexec, doas, sup, sud. For any
|
||||
alternative to work the executable must be included in the current
|
||||
PATH.
|
||||
|
||||
.B
|
||||
.IP "-h"
|
||||
@ -329,14 +356,14 @@ Switch to this TTY terminal when dropping privileges.
|
||||
|
||||
Hooks are special files that can be placed inside the tomb and trigger
|
||||
actions when it is opened and closed; there are two kinds of such
|
||||
files: \fIbind-hooks\fR and \fIpost-hooks\fR can be placed in the
|
||||
files: \fIbind-hooks\fR and \fIexec-hooks\fR can be placed in the
|
||||
base root of the tomb.
|
||||
|
||||
.B
|
||||
.IP "bind-hooks"
|
||||
This hook file consists of a simple text file named \fIbind-hooks\fR
|
||||
containing a two column list of paths to files or directories inside
|
||||
the tomb. The files and directories will be be made directly
|
||||
the tomb. The files and directories will be made directly
|
||||
accessible by the tomb \fIopen\fR command inside the current user's
|
||||
home directory. Tomb uses internally the "mount \-o bind" command to
|
||||
bind locations inside the tomb to locations found in $HOME. In the
|
||||
@ -363,9 +390,9 @@ command.
|
||||
.SH PRIVILEGE ESCALATION
|
||||
|
||||
The tomb commandline tool needs to acquire super user rights to
|
||||
execute most of its operations: to do so it uses sudo(8), while
|
||||
pinentry(1) is adopted to collect passwords from the user. Tomb
|
||||
executes as super user only when required.
|
||||
execute most of its operations: so it uses sudo(8) or other configured
|
||||
tools, while pinentry(1) is adopted to collect passwords from the
|
||||
user. Tomb executes as super user only when required.
|
||||
|
||||
To be made available on multi user systems, the superuser execution of
|
||||
the tomb script can be authorized for users without jeopardizing the
|
||||
@ -386,12 +413,12 @@ Defaults!TOMB !syslog
|
||||
|
||||
Password input is handled by the pinentry program: it can be text
|
||||
based or graphical and is usually configured with a symlink. When
|
||||
using Tomb in X11 it is better to use a graphical pinentry-gtk2 or
|
||||
pinentry-qt because it helps preventing keylogging by other X
|
||||
clients. When using it from a remote ssh connection it might be
|
||||
necessary to force use of pinentry-curses for instance by unsetting
|
||||
the DISPLAY environment var.
|
||||
|
||||
using Tomb in a graphical environment (X11 or Wayland) it is better
|
||||
to use either pinentry-gtk2 (deprecated), pinentry-gnome or
|
||||
pinentry-qt because it helps preventing keylogging by other clients.
|
||||
When using it from a remote ssh connection it might be necessary to
|
||||
force use of pinentry-tty for instance by unsetting the DISPLAY (X11)
|
||||
or WAYLAND_DISPLAY (Wayland) environment var.
|
||||
|
||||
.SH SWAP
|
||||
|
||||
@ -426,7 +453,7 @@ seized devices and forensic analysis of files and blocks on disc.
|
||||
|
||||
For instance to eliminate any trace of tomb usage from the shell
|
||||
history ZSh users can activate the "HISTIGNORESPACE" feature and
|
||||
prefix all invokations of tomb with a blank space, including two lines
|
||||
prefix all invocations of tomb with a blank space, including two lines
|
||||
in ".zshrc":
|
||||
|
||||
.EX
|
||||
@ -434,16 +461,6 @@ export HISTIGNORESPACE=1
|
||||
alias tomb=' tomb'
|
||||
.EE
|
||||
|
||||
.SH PASSWORD INPUT
|
||||
|
||||
Tomb uses the external program "pinentry" to let users type the key password into a terminal or a graphical window. This program works in conjunction with "gpg-agent", a daemon running in background to facilitate secret key management with gpg. It is recommended one runs "gpg-agent" launching it from the X session initialization ("~/.xsession" or "~/.xinitrc" files) with this command:
|
||||
|
||||
.EX
|
||||
eval $(gpg-agent --daemon --write-env-file "${HOME}/.gpg-agent-info")
|
||||
.EE
|
||||
|
||||
In the future it may become mandatory to run gpg-agent when using tomb.
|
||||
|
||||
.SH SHARE A TOMB
|
||||
A tomb key can be encrypted with more than one recipient. Therefore, a
|
||||
tomb can be shared between different users. The recipients are given
|
||||
@ -456,24 +473,6 @@ its copies are destroyed. The \fI-r\fR option can be used in the tomb
|
||||
commands: \fIopen\fR, \fIforge\fR \fIsetkey\fR, \fIpasswd\fR,
|
||||
\fIbury\fR, \fIexhume\fR and \fIresize\fR.
|
||||
|
||||
.SH SPHINX (PAKE)
|
||||
|
||||
Using the package libsphinx
|
||||
.UR https://github.com/stef/libsphinx
|
||||
.UE
|
||||
and its python client/daemon implementation pwdsphinx
|
||||
.UR https://github.com/stef/pwdsphinx
|
||||
.UE
|
||||
is possible to store and retrieve safely the password that locks the
|
||||
tomb. Using this feature will make it impossible to retrieve the
|
||||
password without the oracle sphinx server running and reachable. Each
|
||||
key entry needs a username and a domain specified on creation and
|
||||
a password that locks it.
|
||||
|
||||
SPHINX makes it impossible to mailiciously retrieve the password
|
||||
locking the tomb key without an attacker accessing both the
|
||||
server, the sphinx password and the tomb key file.
|
||||
|
||||
.SH EXAMPLES
|
||||
|
||||
.IP \(bu
|
||||
@ -523,13 +522,14 @@ keeping all its profile data inside it:
|
||||
|
||||
.EX
|
||||
tomb open FOX.tomb -k FOX.tomb.key
|
||||
cat <<EOF > /media/FOX.tomb/post-hooks
|
||||
cat <<EOF > /media/FOX.tomb/exec-hooks
|
||||
#!/bin/sh
|
||||
if [ "$1" = "open" ]; then
|
||||
firefox -no-remote -profile "$2"/firefox-pro &
|
||||
fi
|
||||
EOF
|
||||
chmod +x /media/FOX.tomb/post-hooks
|
||||
chmod +x /media/FOX.tomb/exec-hooks
|
||||
mkdir /media/FOX.tomb/firefox-pro
|
||||
.EE
|
||||
|
||||
.IP \(bu
|
||||
@ -540,7 +540,7 @@ Script a tomb to archive Pictures using Shotwell, launching it on open:
|
||||
cat <<EOF > /media/Pictures.tomb/bind-hooks
|
||||
Pictures Pictures
|
||||
EOF
|
||||
cat <<EOF > /media/Pictures.tomb/post-hooks
|
||||
cat <<EOF > /media/Pictures.tomb/exec-hooks
|
||||
#!/bin/sh
|
||||
if [ "$1" = "open" ]; then
|
||||
which shotwell > /dev/null
|
||||
@ -549,7 +549,7 @@ if [ "$1" = "open" ]; then
|
||||
fi
|
||||
fi
|
||||
EOF
|
||||
chmod +x /media/Pictures.tomb/post-hooks
|
||||
chmod +x /media/Pictures.tomb/exec-hooks
|
||||
.EE
|
||||
|
||||
.SH BUGS
|
||||
@ -562,7 +562,7 @@ channel on \fIhttps://irc.dyne.org\fR.
|
||||
|
||||
.SH COPYING
|
||||
|
||||
This manual is Copyright (c) 2011-2019 by Denis Roio <\fIjaromil@dyne.org\fR>
|
||||
This manual is Copyright (c) 2011-2021 by Denis Roio <\fIjaromil@dyne.org\fR>
|
||||
|
||||
This manual includes contributions by Boyska and Hellekin O. Wolf.
|
||||
|
||||
|
Binary file not shown.
@ -1647,7 +1647,7 @@ change_tomb_key() {
|
||||
|
||||
_sudo cryptsetup luksClose "${mapper}" || _failure "Unexpected error in luksClose."
|
||||
|
||||
_success "Succesfully changed key for tomb: ::1 tomb file::" $TOMBFILE
|
||||
_success "Successfully changed key for tomb: ::1 tomb file::" $TOMBFILE
|
||||
_message "The new key is: ::1 new key::" $TOMBKEYFILE
|
||||
|
||||
return 0
|
||||
|
5
extras/cloak/Makefile
Normal file
5
extras/cloak/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
install:
|
||||
install -Dm755 cloakify.py ${DESTDIR}${PREFIX}/bin/cloakify
|
||||
install -Dm755 decloakify.py ${DESTDIR}${PREFIX}/bin/decloakify
|
3
extras/cloak/README.md
Normal file
3
extras/cloak/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Cloakify steganography into text files
|
||||
|
||||
Original repo: https://github.com/asrabon/Cloakify-3
|
66
extras/cloak/ciphers/amphibians
Normal file
66
extras/cloak/ciphers/amphibians
Normal file
@ -0,0 +1,66 @@
|
||||
Allophrynidae
|
||||
Pipidae
|
||||
Dicroglossidae
|
||||
Myobatrachidae
|
||||
Mavortium
|
||||
Indotyphlidae
|
||||
Elongatus
|
||||
Croceater
|
||||
Xanthoptica
|
||||
Telmatobiidae
|
||||
Arthroleptidae
|
||||
Phrynobatrachidae
|
||||
Hynobiidae
|
||||
Rivularis
|
||||
Torosa
|
||||
Ranidae
|
||||
Leptodactylidae
|
||||
Dendrobatidae
|
||||
Alsodidae
|
||||
Eleutherodactylidae
|
||||
Bufonidae
|
||||
Craugastoridae
|
||||
Ambystomatidae
|
||||
Hylodidae
|
||||
Croceum
|
||||
Sierrae
|
||||
Ambystoma
|
||||
Micrixalidae
|
||||
Nyctibatrachidae
|
||||
Taricha
|
||||
Typhlonectidae
|
||||
Attenuatus
|
||||
Brachycephalidae
|
||||
Dicamptodon
|
||||
Platycephalus
|
||||
Ichthyophiidae
|
||||
Centrolenidae
|
||||
Plethodontidae
|
||||
Oregonensis
|
||||
Hyperoliidae
|
||||
Batrachoseps
|
||||
Hylidae
|
||||
Rhacophoridae
|
||||
Diabolicus
|
||||
Ensatina
|
||||
Gavilanensis
|
||||
Nigriventris
|
||||
Californiense
|
||||
Rhyacotritonidae
|
||||
Salamandridae
|
||||
Altasierrae
|
||||
Plethodon
|
||||
Megophryidae
|
||||
Sigillatum
|
||||
Variegatus
|
||||
Tenebrosus
|
||||
Microhylidae
|
||||
Pacificus
|
||||
Odontobatrachidae
|
||||
Ceratobatrachidae
|
||||
Odontophrynidae
|
||||
Strabomantidae
|
||||
Mantellidae
|
||||
Hydromantes
|
||||
Siphonopidae
|
||||
Pyxicephalidae
|
66
extras/cloak/ciphers/belgianBeers
Normal file
66
extras/cloak/ciphers/belgianBeers
Normal file
@ -0,0 +1,66 @@
|
||||
Nondedju
|
||||
St. Paul Double
|
||||
Lesage Dubbel
|
||||
La Namuroise
|
||||
Saint-Monon Ambrée
|
||||
Belle-Vue Kriek Classique
|
||||
Floris Framboise
|
||||
Corsendonk Triple 11.11.11
|
||||
Keizer Karel Robijn Rood
|
||||
Waase Wolf
|
||||
Horst bier
|
||||
Morpheus Tripel
|
||||
Mageleno
|
||||
Gordon Finest Copper
|
||||
St. Benoit Blonde
|
||||
Waterloo Tripel 7 Blond
|
||||
Totentrekker
|
||||
Molse Tripel
|
||||
Geuze Mariage Parfait
|
||||
Quest
|
||||
Limerick
|
||||
Buffalo Bitter
|
||||
Mongozo Palmnut
|
||||
La Waterlootoise
|
||||
Serafijn Tripel
|
||||
Lindemans Apple
|
||||
Sint-Gummarus Tripel
|
||||
Steendonk
|
||||
Chimay Wit
|
||||
Podge Oak Aged Stout
|
||||
Liefmans Frambozenbier
|
||||
Louwaege Faro
|
||||
Ypres
|
||||
Hapkin
|
||||
Affligem 950 Cuvee
|
||||
Caulier Brune
|
||||
Hoppe
|
||||
Joseph
|
||||
Florilège de Rose
|
||||
Saison de Dottignies
|
||||
Shark Pants
|
||||
Pikkeling Tripel
|
||||
Den Twaalf
|
||||
Antiek Blond
|
||||
Belgoo Luppoo
|
||||
Cambrinus
|
||||
Adelardus
|
||||
La Rulles Blonde
|
||||
Kapel van Viven Blond
|
||||
Montagnarde Altitude 6
|
||||
Ramée Triple Blond
|
||||
Abbay d'Aulne Triple Blonde
|
||||
't Smisje Calva Reserva
|
||||
De Koninck Winter
|
||||
Holger
|
||||
Zonderik 100
|
||||
Elliot Brew
|
||||
Abbay d'Aulne Val de Sambre
|
||||
Sur-les-Bois Blonde
|
||||
Schaarbeekse Oude Kriek 3 Fonteinen
|
||||
Lustem
|
||||
Rodenbach
|
||||
Vossen met de Meynen Blond
|
||||
Xenophon’s Wine
|
||||
Westhoek XX
|
||||
Brussels Fruit Beer "Red Fruit"
|
107
extras/cloak/ciphers/desserts
Normal file
107
extras/cloak/ciphers/desserts
Normal file
@ -0,0 +1,107 @@
|
||||
honey
|
||||
jelly
|
||||
lollipop
|
||||
spumoni
|
||||
milkshake
|
||||
shortcake
|
||||
souffle
|
||||
flower
|
||||
fondant
|
||||
crunch
|
||||
pineapple
|
||||
marionberry
|
||||
lime
|
||||
pudding
|
||||
sugar
|
||||
caramel
|
||||
granita
|
||||
zest
|
||||
brittle
|
||||
liquer
|
||||
bun
|
||||
toffee
|
||||
ginger
|
||||
custard
|
||||
cookie
|
||||
sucker
|
||||
pistachio
|
||||
meringue
|
||||
eggs
|
||||
peach
|
||||
buttermilk
|
||||
turnover
|
||||
biscuits
|
||||
turtle
|
||||
puffs
|
||||
doughnut
|
||||
apricot
|
||||
nutmeg
|
||||
gingerbread
|
||||
cherry
|
||||
truffle
|
||||
turnovers
|
||||
licorice
|
||||
mousse
|
||||
muffins
|
||||
raspberry
|
||||
sorbet
|
||||
streusel
|
||||
candy
|
||||
torte
|
||||
syrup
|
||||
terrine
|
||||
curd
|
||||
hazelnut
|
||||
brownie
|
||||
strawberries
|
||||
blueberry
|
||||
coconut
|
||||
butterscotch
|
||||
cookies
|
||||
huckleberry
|
||||
icing
|
||||
walnut
|
||||
pie
|
||||
snickerdoodles
|
||||
cannoli
|
||||
marzipan
|
||||
cake
|
||||
compote
|
||||
bonbon
|
||||
glaze
|
||||
flan
|
||||
cane
|
||||
foster
|
||||
sherbet
|
||||
ganache
|
||||
cream
|
||||
buttercream
|
||||
jam
|
||||
cobbler
|
||||
tirimisu
|
||||
creme
|
||||
cupcake
|
||||
cinnamon
|
||||
mint
|
||||
vanilla
|
||||
éclair
|
||||
taffy
|
||||
orange
|
||||
almond
|
||||
rhubarb
|
||||
pastry
|
||||
brulee
|
||||
lemon
|
||||
cheesecake
|
||||
chocolate
|
||||
donut
|
||||
sundae
|
||||
peach pie
|
||||
shortbread
|
||||
frosting
|
||||
parfaits
|
||||
blackberry
|
||||
popsicle
|
||||
confection
|
||||
crepe
|
||||
macaroon
|
100
extras/cloak/ciphers/dessertsArabic
Normal file
100
extras/cloak/ciphers/dessertsArabic
Normal file
@ -0,0 +1,100 @@
|
||||
سلحفاة
|
||||
كاب كيك
|
||||
ترين
|
||||
معجنات
|
||||
مرزبانية حلوى لوز وسكر
|
||||
اللبن المخفوق
|
||||
مخيض اللبن
|
||||
كعكة فواكه
|
||||
القاناش
|
||||
مصاصة
|
||||
ايكلير
|
||||
زهرة
|
||||
أقراص سكرية
|
||||
دوران
|
||||
بروليه
|
||||
عرق السوس
|
||||
المصاصة
|
||||
بقلمي
|
||||
مشمش
|
||||
نفث
|
||||
الإسكافي
|
||||
تبرع
|
||||
تيريميسو
|
||||
كلس
|
||||
تلذذ
|
||||
.توت
|
||||
لوز
|
||||
كعكة الغريبة
|
||||
فراولة
|
||||
كرز
|
||||
جنية سمراء صغيرة
|
||||
تحولات
|
||||
خبز الزنجبيل
|
||||
سطح أملس
|
||||
فستق
|
||||
تورتى
|
||||
كومبوت
|
||||
نعناع
|
||||
نبات
|
||||
شوكولاتة
|
||||
قصب
|
||||
كعكة
|
||||
كريم
|
||||
كريب
|
||||
مرنغ
|
||||
نفيخة
|
||||
الكعك
|
||||
البون بون
|
||||
كاسترد
|
||||
أناناس
|
||||
الكرمل
|
||||
يكر
|
||||
عسل
|
||||
الزبد
|
||||
شراب مركز
|
||||
السكر
|
||||
شربات
|
||||
خوخ
|
||||
جوزة الطيب
|
||||
الموسية
|
||||
سكريات الطوفي حلوى
|
||||
راوند
|
||||
بندق
|
||||
تخثر
|
||||
فطيرة الجبن
|
||||
سبوموني
|
||||
الحاضنة
|
||||
زنجبيل
|
||||
فطيرة
|
||||
كوكي
|
||||
البسكويت
|
||||
بسكويت
|
||||
جرانيتا
|
||||
صقيع
|
||||
البرتقالي
|
||||
جوزة الهند
|
||||
بودنغ
|
||||
حلوى
|
||||
الكمأة
|
||||
توت العُليق
|
||||
معكرون نوع حلوي
|
||||
كانولي
|
||||
فطيرة الخوخ
|
||||
سحق
|
||||
هش
|
||||
قرفة
|
||||
ليمون
|
||||
هلام
|
||||
جوز
|
||||
الفانيليا
|
||||
بارفيتس
|
||||
مثلجات
|
||||
إبله
|
||||
بلاك بيري
|
||||
[ستريوسل]
|
||||
حلوى من سكر أسمر وزبدة
|
||||
الكعك المحلى بالسكر
|
||||
مربى
|
||||
بيض
|
||||
تثليج
|
94
extras/cloak/ciphers/dessertsChinese
Normal file
94
extras/cloak/ciphers/dessertsChinese
Normal file
@ -0,0 +1,94 @@
|
||||
蛋糕
|
||||
甜甜圈
|
||||
草莓
|
||||
橙
|
||||
焦糖
|
||||
糖浆
|
||||
越橘
|
||||
姜
|
||||
酥皮
|
||||
蛋白杏仁饼干
|
||||
榛子
|
||||
乳蛋糕
|
||||
果仁蛋糕
|
||||
皮匠
|
||||
香草
|
||||
培育
|
||||
周转
|
||||
糖粉奶油细末
|
||||
杯形饼
|
||||
棒糖
|
||||
软糖
|
||||
酸橙
|
||||
脆
|
||||
酥
|
||||
棒冰
|
||||
核桃
|
||||
覆盆子
|
||||
包子
|
||||
杏
|
||||
果盘
|
||||
樱桃
|
||||
乳酪蛋糕
|
||||
紧缩
|
||||
糖
|
||||
糖果
|
||||
柠檬
|
||||
松露
|
||||
失误
|
||||
奶油曲奇
|
||||
巧克力
|
||||
龟
|
||||
奶糖
|
||||
桃子馅饼
|
||||
甘草
|
||||
桃
|
||||
凝乳
|
||||
杂音
|
||||
太妃糖
|
||||
热情
|
||||
圣代
|
||||
冻糕
|
||||
布朗尼
|
||||
格兰尼塔
|
||||
果酱
|
||||
果冻
|
||||
布丁
|
||||
鸡蛋
|
||||
黑莓
|
||||
开心果
|
||||
奶昔
|
||||
肉桂
|
||||
甘蔗
|
||||
薄荷
|
||||
酪
|
||||
糕点
|
||||
杏仁
|
||||
釉
|
||||
肉豆蔻
|
||||
冰糕
|
||||
松饼
|
||||
果子露
|
||||
花
|
||||
绉
|
||||
菠萝
|
||||
大黄
|
||||
蓝莓
|
||||
沙锅
|
||||
结霜
|
||||
邦邦
|
||||
蜜饯
|
||||
吸盘
|
||||
姜饼
|
||||
香炸奶酪卷
|
||||
奶油
|
||||
伽纳彻
|
||||
曲奇饼
|
||||
椰子
|
||||
果馅饼
|
||||
馅饼
|
||||
摩丝
|
||||
积冰
|
||||
泡芙
|
||||
蜂蜜
|
||||
饼干
|
84
extras/cloak/ciphers/dessertsHindi
Normal file
84
extras/cloak/ciphers/dessertsHindi
Normal file
@ -0,0 +1,84 @@
|
||||
केक
|
||||
बादाम का मीठा हलुआ
|
||||
टुकड़े
|
||||
कुचले हुए फल
|
||||
जायफल
|
||||
कलाकंद
|
||||
कुकी
|
||||
कप केक
|
||||
दालचीनी
|
||||
क्रेप
|
||||
कारोबार
|
||||
चीज़केक
|
||||
खुबानी
|
||||
बटरस्कॉच
|
||||
सिरप
|
||||
टाफ़ी
|
||||
जाम
|
||||
जिंजरब्रेड
|
||||
नारंगी
|
||||
कुकीज़
|
||||
ठंडा करना
|
||||
ब्राउनी
|
||||
पाई
|
||||
शहद
|
||||
क्रीम
|
||||
एक प्रकार का फल
|
||||
बिस्कुट
|
||||
आड़ू
|
||||
चीनी
|
||||
अदरक
|
||||
मिठाई
|
||||
टोफ़ी
|
||||
नद्यपान
|
||||
नाज़ुक
|
||||
चेरी
|
||||
चूसने की मिठाई
|
||||
वनीला
|
||||
दही
|
||||
दिलचस्पी
|
||||
गन्ना
|
||||
पिस्ता
|
||||
चॉकलेट
|
||||
मोची
|
||||
गनाचे
|
||||
अंडे
|
||||
शीशे का आवरण
|
||||
कचौड़ी
|
||||
पेस्ट्री
|
||||
छाछ
|
||||
जेली
|
||||
नारियल
|
||||
बन
|
||||
चूना
|
||||
कश
|
||||
की कमी
|
||||
फ़्लान
|
||||
कारमेल
|
||||
नींबू
|
||||
शर्बत
|
||||
आड़ु पाई
|
||||
मिल्कशेक
|
||||
फूल
|
||||
डोनट
|
||||
स्ट्रॉबेरीज
|
||||
पालक
|
||||
अखरोट
|
||||
ब्लूबेरी
|
||||
पुदीना
|
||||
मलाई
|
||||
मानसिक शांति
|
||||
हेज़लनट
|
||||
ब्लैकबेरी
|
||||
बादाम
|
||||
रसभरी
|
||||
कैंडी
|
||||
मूस
|
||||
टर्नओवर
|
||||
बॉन बॉन
|
||||
कछुआ
|
||||
चूसने वाला
|
||||
कस्टर्ड
|
||||
कुकुरमुत्ता
|
||||
पुडिंग
|
||||
अनानास
|
92
extras/cloak/ciphers/dessertsPersian
Normal file
92
extras/cloak/ciphers/dessertsPersian
Normal file
@ -0,0 +1,92 @@
|
||||
آناناس
|
||||
تخم مرغ
|
||||
بستنی چوبی
|
||||
حجم معاملات
|
||||
بستنی و مغز گردو
|
||||
نان شیرینی مرکب از شکر و زرده تخم مرغ و بادام
|
||||
فندق
|
||||
زنجبیل
|
||||
ژله
|
||||
گردو
|
||||
دونات
|
||||
پینه دوز
|
||||
لاک پشت
|
||||
مستی
|
||||
زغال اخته
|
||||
پسته
|
||||
سرخ
|
||||
طفل شیرخوار
|
||||
گل
|
||||
میلک شیک
|
||||
شیرینی زنجفیلی
|
||||
شکننده
|
||||
جوز
|
||||
نارگیل
|
||||
پودینگ
|
||||
نارنجی
|
||||
ابدوغ
|
||||
کلوچه
|
||||
کمپوت
|
||||
بحران
|
||||
شکلات
|
||||
هلو
|
||||
شربت
|
||||
کرپ
|
||||
کیک تخم مرغ و شکر و مغز گردو
|
||||
تمشک
|
||||
لیمو شیرین
|
||||
عسل
|
||||
گردش
|
||||
زردالو
|
||||
کیک میوه
|
||||
پای
|
||||
کیک
|
||||
بستنی میوه
|
||||
تافی
|
||||
کرم رنگ
|
||||
کوکی
|
||||
اب نبات چوبی
|
||||
نوعی کیک میوه دار
|
||||
توت سیاه
|
||||
ریواس
|
||||
فاستر
|
||||
وانیل
|
||||
نبات
|
||||
بیسکویت
|
||||
قارچ خوراکی دنبلان
|
||||
لیکور
|
||||
شیرینی
|
||||
شکر و تخم مرغ
|
||||
بستنی میوه و مغز بادام و میوه جات ایتالیایی
|
||||
یکجور دوربین عکاسی
|
||||
شیرین بیان
|
||||
کماج
|
||||
فوندانت
|
||||
نیشکر
|
||||
کرم
|
||||
پاف
|
||||
قند
|
||||
نعناع
|
||||
موس
|
||||
گرانیت
|
||||
دارچین
|
||||
اهک
|
||||
پوشش
|
||||
گراوند
|
||||
بادام
|
||||
فیالبداهه
|
||||
پای هلو
|
||||
شیرینی خامهدار و بستنی دار
|
||||
کیک پنیر
|
||||
نوعی کیک کوچک
|
||||
توت فرنگی
|
||||
رنگ زرد
|
||||
مربا
|
||||
سوفله
|
||||
کاستارد
|
||||
درخت زغال اخته
|
||||
کشک
|
||||
گیلاس
|
||||
مزه
|
||||
نان روغنی
|
||||
لعاب
|
90
extras/cloak/ciphers/dessertsRussian
Normal file
90
extras/cloak/ciphers/dessertsRussian
Normal file
@ -0,0 +1,90 @@
|
||||
присоска
|
||||
праздничный торт
|
||||
малина
|
||||
трюфель
|
||||
лесной орех
|
||||
леденец
|
||||
кремовый
|
||||
песочное печенье
|
||||
ананас
|
||||
мускатный орех
|
||||
лайм
|
||||
печенье
|
||||
сироп
|
||||
абрикос
|
||||
лимон
|
||||
кондитерские изделия
|
||||
миндальное печенье
|
||||
эклер
|
||||
конфета
|
||||
имбирный пряник
|
||||
чизкейк
|
||||
ваниль
|
||||
крем
|
||||
сапожник
|
||||
флан
|
||||
цветок
|
||||
мусс
|
||||
творог
|
||||
шоколад
|
||||
брюле
|
||||
хруст
|
||||
кексы
|
||||
черепаха
|
||||
карамель
|
||||
имбирь
|
||||
обороты
|
||||
иней
|
||||
желе
|
||||
пирог
|
||||
яйца
|
||||
домовой
|
||||
фисташковый
|
||||
парфе
|
||||
варенье
|
||||
сахар
|
||||
кекс
|
||||
грецкий орех
|
||||
глазурь
|
||||
мята
|
||||
обледенение
|
||||
затяжек
|
||||
булочка
|
||||
эскимо
|
||||
конфеты
|
||||
тростник
|
||||
ликер
|
||||
вишня
|
||||
кокос
|
||||
суфле
|
||||
персиковый пирог
|
||||
корица
|
||||
помадка
|
||||
молочный коктейль
|
||||
пудинг
|
||||
черника
|
||||
ежевика
|
||||
ревень
|
||||
меренга
|
||||
ириски
|
||||
персик
|
||||
ломкий
|
||||
пломбир
|
||||
ириска
|
||||
пончик
|
||||
миндальный
|
||||
блюдо из дичи
|
||||
марципан
|
||||
лакрица
|
||||
способствовать
|
||||
заварной крем
|
||||
мед
|
||||
компот
|
||||
пахта
|
||||
цедра
|
||||
оборот
|
||||
канноли
|
||||
оранжевый
|
||||
шербет
|
||||
клубника
|
||||
креп
|
104
extras/cloak/ciphers/dessertsSwedishChef
Normal file
104
extras/cloak/ciphers/dessertsSwedishChef
Normal file
@ -0,0 +1,104 @@
|
||||
boon
|
||||
meelksheke-a
|
||||
brooneee-a
|
||||
mooffffeens
|
||||
coosterd
|
||||
bleckberry
|
||||
ceennemun
|
||||
tureemisoo
|
||||
teffffy
|
||||
cubbler
|
||||
guneche-a
|
||||
fundunt
|
||||
pooddeeng
|
||||
perffeeets
|
||||
shurtbreed
|
||||
meceruun
|
||||
syroop
|
||||
flooer
|
||||
meent
|
||||
suooffffle-a
|
||||
cuukeee-a
|
||||
merzeepun
|
||||
bootterscutch
|
||||
creme-a
|
||||
soondee-a
|
||||
streoosel
|
||||
creem
|
||||
ceremel
|
||||
cherry
|
||||
sooger
|
||||
shurtceke-a
|
||||
hoockleberry
|
||||
hezelnoot
|
||||
geenger
|
||||
oorunge-a
|
||||
tuffffee-a
|
||||
muoosse-a
|
||||
cunnulee
|
||||
sherbet
|
||||
jelly
|
||||
cheeseceke-a
|
||||
chuculete-a
|
||||
cune-a
|
||||
coopceke-a
|
||||
cuukeees
|
||||
surbet
|
||||
crepe-a
|
||||
iceeng
|
||||
duooghnoot
|
||||
pestry
|
||||
toortle-a
|
||||
mereengooe-a
|
||||
gruneeta
|
||||
leeme-a
|
||||
epreecut
|
||||
sneeckerduudles
|
||||
toornufers
|
||||
beescooits
|
||||
gleze-a
|
||||
rhooberb
|
||||
huney
|
||||
coord
|
||||
lulleepup
|
||||
bunbun
|
||||
dunoot
|
||||
ceke-a
|
||||
breettle-a
|
||||
croonch
|
||||
leeqooer
|
||||
frusteeng
|
||||
pupseecle-a
|
||||
spoomunee
|
||||
cundy
|
||||
pooffffs
|
||||
soocker
|
||||
blooeberry
|
||||
toornufer
|
||||
nootmeg
|
||||
broolee-a
|
||||
lemun
|
||||
cunffecshun
|
||||
terreene-a
|
||||
respberry
|
||||
elmund
|
||||
turte-a
|
||||
velnoot
|
||||
mereeunberry
|
||||
fuster
|
||||
peee-a
|
||||
peech
|
||||
trooffffle-a
|
||||
cumpute-a
|
||||
leecurice-a
|
||||
cucunoot
|
||||
peeneepple-a
|
||||
jem
|
||||
geengerbreed
|
||||
iggs
|
||||
flun
|
||||
zest
|
||||
peestechiu
|
||||
strevberreees
|
||||
écleur
|
||||
funeella
|
86
extras/cloak/ciphers/dessertsThai
Normal file
86
extras/cloak/ciphers/dessertsThai
Normal file
@ -0,0 +1,86 @@
|
||||
นมผสมไอศกรีม
|
||||
ไข่
|
||||
แห้ว
|
||||
เปลือกน้ำฅาล
|
||||
ครีม
|
||||
ผลไม้ชนิดหนึ่ง
|
||||
ผลไม้แช่อิ่ม
|
||||
ขนมเมอร์แรง
|
||||
ฉาบ
|
||||
ความเอร็ดอร่อย
|
||||
คุกกี้
|
||||
โดนัท
|
||||
ลูกจันทน์เทศ
|
||||
นมเปรี้ยว
|
||||
พาย
|
||||
ขนมชนิดร่วน
|
||||
ไอติม
|
||||
ราสเบอร์รี่
|
||||
ทอฟฟี่
|
||||
เฮเซลนัท
|
||||
ขนมปิ้ง
|
||||
อ้อย
|
||||
ทำเหรียญ
|
||||
น้ำผึ้ง
|
||||
มะพร้าว
|
||||
กาละแม
|
||||
อุปถัมภ์
|
||||
บัตเตอร์
|
||||
อาหารตีให้เป็นฟอง
|
||||
ขนมปังขิง
|
||||
เชอร์รี่
|
||||
พุดดิ้ง
|
||||
ผักชนิดหนึ่ง
|
||||
มวย
|
||||
ผลประกอบการ
|
||||
สีส้ม
|
||||
ต้นมันฮ่อ
|
||||
ลูกอม
|
||||
อัลมอนด์
|
||||
ขนมแมคะรูน
|
||||
สตรอเบอร์รี่
|
||||
เครื่องปรุงอาหารมาร์ซิปัน
|
||||
มะนาว
|
||||
ขนมปังกรอบ
|
||||
ลูกกวาด
|
||||
คัพเค้ก
|
||||
ฅกประหม่า
|
||||
ผี
|
||||
อบเชย
|
||||
ขนมชนิดหนึ่ง
|
||||
น้ำเชื่อม
|
||||
เต่า
|
||||
แอปริคอท
|
||||
ขนมเค้กเนยแข็ง
|
||||
พาย ลูกพีช
|
||||
เครื่องดื่มเชอร์เบ็ท
|
||||
วุ้น
|
||||
เค้ก
|
||||
กระทืบ
|
||||
ช็อคโกแลต
|
||||
มูสส์
|
||||
แพรย่น
|
||||
ผลไม้ดำนำ้เงินลูเล็ก ๆ
|
||||
ขิง
|
||||
คัสตาร์
|
||||
ไอศกรีมใส่ผลไม้
|
||||
แยม
|
||||
เครื่องดูด
|
||||
มัฟฟิน
|
||||
ขนมที่ติดกับปลายไม้
|
||||
ดอกไม้
|
||||
น้ำตาล
|
||||
หลากสี
|
||||
บลูเบอร์รี่
|
||||
พีช
|
||||
วานิลลา
|
||||
เชอร์เบท
|
||||
คุ้กกี้
|
||||
พิสตาเชีย
|
||||
เคลือบน้ำแข็ง
|
||||
เปราะ
|
||||
พัฟ
|
||||
พายผลไม้
|
||||
พืชชะเอ็ม
|
||||
สับปะรด
|
||||
บัตเตอร์ครีม
|
70
extras/cloak/ciphers/emoji
Normal file
70
extras/cloak/ciphers/emoji
Normal file
@ -0,0 +1,70 @@
|
||||
😀
|
||||
😴
|
||||
😜
|
||||
😝
|
||||
😩
|
||||
😃
|
||||
😛
|
||||
😕
|
||||
😏
|
||||
👊
|
||||
🙉
|
||||
😿
|
||||
😅
|
||||
😁
|
||||
😭
|
||||
🐱
|
||||
😸
|
||||
🙌
|
||||
😓
|
||||
🙈
|
||||
🐨
|
||||
😽
|
||||
🐵
|
||||
😮
|
||||
😈
|
||||
😆
|
||||
😑
|
||||
😶
|
||||
🐔
|
||||
😂
|
||||
😪
|
||||
😥
|
||||
🙆
|
||||
😲
|
||||
🙇
|
||||
😾
|
||||
😹
|
||||
🙍
|
||||
😗
|
||||
😳
|
||||
😼
|
||||
😧
|
||||
🐸
|
||||
🙀
|
||||
🖖
|
||||
😌
|
||||
😟
|
||||
🙅
|
||||
😬
|
||||
🙊
|
||||
🐼
|
||||
😄
|
||||
😣
|
||||
🐻
|
||||
😻
|
||||
😱
|
||||
😯
|
||||
😷
|
||||
😊
|
||||
🐂
|
||||
🐰
|
||||
😵
|
||||
😰
|
||||
🙏
|
||||
🙎
|
||||
😺
|
||||
🙋
|
||||
😫
|
||||
😡
|
||||
😙
|
65
extras/cloak/ciphers/evadeAV
Normal file
65
extras/cloak/ciphers/evadeAV
Normal file
@ -0,0 +1,65 @@
|
||||
4
|
||||
v
|
||||
q
|
||||
m
|
||||
0
|
||||
B
|
||||
j
|
||||
u
|
||||
E
|
||||
e
|
||||
g
|
||||
J
|
||||
w
|
||||
y
|
||||
Y
|
||||
Q
|
||||
D
|
||||
H
|
||||
t
|
||||
x
|
||||
i
|
||||
3
|
||||
6
|
||||
f
|
||||
O
|
||||
C
|
||||
9
|
||||
N
|
||||
a
|
||||
T
|
||||
Z
|
||||
F
|
||||
A
|
||||
5
|
||||
G
|
||||
M
|
||||
h
|
||||
s
|
||||
o
|
||||
7
|
||||
l
|
||||
U
|
||||
k
|
||||
R
|
||||
L
|
||||
X
|
||||
n
|
||||
r
|
||||
W
|
||||
d
|
||||
P
|
||||
K
|
||||
S
|
||||
I
|
||||
c
|
||||
=
|
||||
+
|
||||
/
|
||||
8
|
||||
V
|
||||
2
|
||||
1
|
||||
p
|
||||
b
|
||||
z
|
199
extras/cloak/ciphers/geoCoordsWorldCapitals
Normal file
199
extras/cloak/ciphers/geoCoordsWorldCapitals
Normal file
@ -0,0 +1,199 @@
|
||||
18°21'N 64°56'W
|
||||
05°50'N 55°10'W
|
||||
00°15'S 78°35'W
|
||||
12°06'N 86°20'W
|
||||
13°50'S 171°50'W
|
||||
14°36'N 61°02'W
|
||||
59°55'N 10°45'E
|
||||
43°52'N 18°26'E
|
||||
50°30'N 30°28'E
|
||||
37°31'N 126°58'E
|
||||
29°18'S 27°30'E
|
||||
06°55'N 158°09'E
|
||||
51°40'S 59°51'W
|
||||
37°58'N 23°46'E
|
||||
01°59'S 30°04'E
|
||||
25°10'S 57°30'W
|
||||
04°00'N 73°28'E
|
||||
35°10'N 33°25'E
|
||||
05°35'N 00°06'W
|
||||
22°35'S 17°04'E
|
||||
03°16'S 29°18'E
|
||||
14°40'N 121°03'E
|
||||
02°02'N 45°25'E
|
||||
52°23'N 04°54'E
|
||||
09°24'S 147°08'E
|
||||
18°40'N 72°20'W
|
||||
46°04'N 14°33'E
|
||||
12°00'S 77°00'W
|
||||
35°54'N 14°31'E
|
||||
27°31'N 89°45'E
|
||||
23°08'N 82°22'W
|
||||
15°31'N 32°35'E
|
||||
17°20'N 61°48'W
|
||||
21°05'N 105°55'E
|
||||
09°00'N 79°25'W
|
||||
33°40'N 73°10'E
|
||||
49°26'N 02°33'W
|
||||
14°00'S 33°48'E
|
||||
59°22'N 24°48'E
|
||||
53°00'S 74°00'E
|
||||
24°45'S 25°57'E
|
||||
18°28'N 66°07'W
|
||||
15°28'S 28°16'E
|
||||
53°52'N 27°30'E
|
||||
42°01'N 21°26'E
|
||||
25°58'S 32°32'E
|
||||
09°05'N 07°32'E
|
||||
11°40'S 43°16'E
|
||||
00°25'N 09°26'E
|
||||
22°17'S 166°30'E
|
||||
25°05'N 77°20'W
|
||||
19°20'N 99°10'W
|
||||
36°30'S 60°00'W
|
||||
45°50'N 15°58'E
|
||||
09°02'N 38°42'E
|
||||
31°57'N 35°52'E
|
||||
17°32'S 149°34'W
|
||||
12°10'N 14°59'E
|
||||
14°16'S 170°43'W
|
||||
35°15'S 149°08'E
|
||||
01°17'S 36°48'E
|
||||
06°23'N 02°42'E
|
||||
12°15'N 01°30'W
|
||||
41°19'S 174°46'E
|
||||
04°23'N 18°35'E
|
||||
46°46'N 56°12'W
|
||||
24°28'N 54°22'E
|
||||
18°00'N 76°50'W
|
||||
40°25'N 03°45'W
|
||||
14°05'N 87°14'W
|
||||
15°02'N 23°34'W
|
||||
13°28'N 16°40'W
|
||||
23°43'N 90°26'E
|
||||
42°45'N 23°20'E
|
||||
09°55'N 84°02'W
|
||||
12°05'N 69°00'W
|
||||
49°37'N 06°09'E
|
||||
48°12'N 16°22'E
|
||||
41°43'N 44°50'E
|
||||
40°10'N 44°31'E
|
||||
04°34'N 74°00'W
|
||||
41°20'N 69°10'E
|
||||
13°10'N 61°10'W
|
||||
41°54'N 12°29'E
|
||||
41°18'N 19°49'E
|
||||
39°55'N 116°20'E
|
||||
44°27'N 26°10'E
|
||||
46°57'N 07°28'E
|
||||
08°31'S 179°13'E
|
||||
24°41'N 46°42'E
|
||||
50°51'N 04°21'E
|
||||
35°44'N 51°30'E
|
||||
12°34'N 07°55'W
|
||||
04°52'N 115°00'E
|
||||
40°29'N 49°56'E
|
||||
27°45'N 85°20'E
|
||||
21°10'S 174°00'W
|
||||
43°55'N 12°30'E
|
||||
42°31'N 01°32'E
|
||||
18°30'N 69°59'W
|
||||
33°20'N 44°30'E
|
||||
05°05'N 52°18'W
|
||||
04°20'S 15°15'E
|
||||
53°21'N 06°15'W
|
||||
00°10'N 06°39'E
|
||||
17°17'N 62°43'W
|
||||
54°38'N 25°19'E
|
||||
32°49'N 13°07'E
|
||||
47°02'N 28°50'E
|
||||
30°01'N 31°14'E
|
||||
14°34'N 17°29'W
|
||||
34°28'N 69°11'E
|
||||
15°47'S 47°55'W
|
||||
13°45'N 100°35'E
|
||||
08°50'S 13°15'E
|
||||
20°10'S 57°30'E
|
||||
00°20'N 32°30'E
|
||||
16°45'N 96°20'E
|
||||
64°10'N 51°35'W
|
||||
12°48'S 45°14'E
|
||||
11°08'N 42°20'E
|
||||
64°10'N 21°57'W
|
||||
55°45'N 37°35'E
|
||||
28°37'N 77°13'E
|
||||
03°09'N 101°41'E
|
||||
60°15'N 25°03'E
|
||||
03°45'N 08°50'E
|
||||
15°12'N 145°45'E
|
||||
15°19'N 38°55'E
|
||||
09°29'N 13°49'W
|
||||
56°53'N 24°08'E
|
||||
29°30'N 48°00'E
|
||||
17°43'S 1°02'E
|
||||
16°20'S 68°10'W
|
||||
08°30'N 13°17'W
|
||||
31°47'N 35°12'E
|
||||
45°20'S 168°43'E
|
||||
48°10'N 17°07'E
|
||||
06°49'N 05°17'W
|
||||
22°12'N 113°33'E
|
||||
06°18'N 10°47'W
|
||||
25°44'S 28°12'E
|
||||
38°33'N 68°48'E
|
||||
48°50'N 02°20'E
|
||||
10°30'N 66°55'W
|
||||
18°27'N 64°37'W
|
||||
36°50'N 10°11'E
|
||||
17°45'S 168°18'E
|
||||
11°33'N 104°55'E
|
||||
08°29'S 125°34'E
|
||||
52°13'N 21°00'E
|
||||
51°36'N 00°05'W
|
||||
33°30'N 36°18'E
|
||||
62°05'N 06°56'W
|
||||
26°10'N 50°30'E
|
||||
15°20'N 61°24'W
|
||||
42°54'N 74°46'E
|
||||
39°91'N 77°02'W
|
||||
06°50'N 58°12'W
|
||||
01°30'N 173°00'E
|
||||
39°57'N 32°54'E
|
||||
44°50'N 20°37'E
|
||||
16°00'N 61°44'W
|
||||
47°29'N 19°05'E
|
||||
17°58'N 102°36'E
|
||||
18°55'S 47°31'E
|
||||
06°09'N 01°20'E
|
||||
11°45'N 15°45'W
|
||||
33°53'N 35°31'E
|
||||
13°40'N 89°10'W
|
||||
34°50'S 56°11'W
|
||||
17°18'N 88°30'W
|
||||
06°09'S 106°49'E
|
||||
47°08'N 09°31'E
|
||||
51°10'N 71°30'E
|
||||
45°27'N 75°42'W
|
||||
52°30'N 13°25'E
|
||||
13°27'N 02°06'E
|
||||
38°00'N 57°50'E
|
||||
50°05'N 14°22'E
|
||||
14°02'N 60°58'W
|
||||
14°40'N 90°22'W
|
||||
03°50'N 11°35'E
|
||||
13°05'N 59°30'W
|
||||
33°24'S 70°40'W
|
||||
07°20'N 134°28'E
|
||||
36°42'N 03°08'E
|
||||
38°42'N 09°10'W
|
||||
12°32'N 70°02'W
|
||||
18°06'S 178°30'E
|
||||
06°08'S 35°45'E
|
||||
59°20'N 18°03'E
|
||||
09°27'S 159°57'E
|
||||
04°09'S 15°12'E
|
||||
23°37'N 58°36'E
|
||||
25°15'N 51°35'E
|
||||
39°09'N 125°30'E
|
||||
19°20'N 81°24'W
|
||||
26°18'S 31°06'E
|
82
extras/cloak/ciphers/geocache
Normal file
82
extras/cloak/ciphers/geocache
Normal file
@ -0,0 +1,82 @@
|
||||
Carley State Park N 44 º 06.717 W 092 º 10.390
|
||||
Scenic State Park N 47 º 42.700 W 093 º 34.167
|
||||
Lake Bronson State Park N 48 º 43.472 W 096 º 37.545
|
||||
Myre-Big Island State Park N 43 º 38.226 W 093 º 18.541
|
||||
Interstate State Park N 45 º 23.518 W 092 º 40.199
|
||||
Tettegouche State Park N 47 º 21.592 W 091 º 16.939
|
||||
Garden Island State Recreation Area N 49 º 10.537 W 094 º 50.031
|
||||
Nerstrand Big Woods State Park N 44 º 20.533 W 093 º 06.339
|
||||
Bear Head Lake State Park N 47o 47.787 W 092o 03.858
|
||||
Cascade River State Park. N 47 º 42.660 W 090 º 30.643
|
||||
Mille Lacs Kathio State Park N 46 º 08.132 W 093 º 43.520
|
||||
Schoolcraft State Park N 47 º 13.390 W 093 º 48.252
|
||||
Frontenac State Park N 44 º 31.428 W 092 º 20.467
|
||||
Temperance River State Park N 47 º 33.241 W 090 º 52.498
|
||||
Cuyuna Country State Recreation Area N 46 º 28.724 W 093 º 58.598
|
||||
Brown’s Creek State Trail N 45 º 04.531 W 092 º 49.776
|
||||
Minnesota Valley State Trail N 44 º 46.901 W 093 º 35.350
|
||||
Lake Louise State Park N 43 º 31.739 W 092 º 31.452
|
||||
Itasca State Park N 47 º 11.488 W 095 º 10.199
|
||||
Split Rock Creek State Park N 43 º 53.664 W 096 º 21.941
|
||||
Kilen Woods State Park N 43 º 43.858 W 095 º 04.101
|
||||
Zippel Bay State Park N 48 º 50.891 W 094 º 50.859
|
||||
Split Rock Lighthouse State Park N 47 º 11.912 W 091 º 22.479
|
||||
George H. Crosby Manitou State Park N 47 º 28.732 W 091 º 06.703
|
||||
Glendalough State Park N 46 º 19.233 W 095 º 40.287
|
||||
Gateway State Trail N 45 º 03.522 W 092 º 55.627
|
||||
Sakatah Lake State Park N 44 º 13.504 W 093 º 31.181
|
||||
Hill Annex Mine State Park N 47 º 19.585 W 093 º 16.697
|
||||
Root River State Trail N 43 º 46.298 W 091 º 38.153
|
||||
Lake Bemidji State Park N 47 º 32.079 W 094 º 49.590
|
||||
La Salle Lake State Recreation Area N 47 º 20.697 W 095 º 09.507
|
||||
Franz Jevne State Park N 48 º 38.526 W 094 º 03.773
|
||||
Minnesota Valley State Recreation Area N 44 º 39.144 W 093 º 42.849
|
||||
Sibley State Park N 45 º 18.865 W 095 º 02.355
|
||||
Blazing Star State Trail N 43 º 38.226 W 093 º 18.541
|
||||
Judge C.R. Magney State Park N 47 º 49.082 W 090 º 03.173
|
||||
Iron Range Off-Highway Vehicle State Recreation Area N 47 º 28.721 W 092 º 26.319
|
||||
Upper Sioux Agency State Park N 44o 44.203 W 095 º 27.571
|
||||
Blue Mounds State Park N 43 º 41.474 W 096 º 11.807
|
||||
Luce Line State Trail N 44 º 59.163 W 093 º 29.651
|
||||
Fort Snelling State Park N 44o 53.349 W 093o 11.014
|
||||
Fort Ridgely State Park N 44 º 27.193 W 094 º 43.607
|
||||
Hayes Lake State Park N 48 º 38.257 W 095 º 32.739
|
||||
Charles A. Lindbergh State Park N 45 º 57.548 W 094 º 23.337
|
||||
Lake Maria State Park N 45 º 19.070 W 093 º 56.139
|
||||
Gooseberry Falls State Park N 47 º 08.463 W 091 º 28.207
|
||||
Savanna Portage State Park N 46 º 49.716 W 093 º 09.031
|
||||
Grand Portage State Park N 48 º 00.200 W 089 º 35.657
|
||||
Greenleaf Lake State Recreation Area N 45 º 00.536 W 094 º 28.491
|
||||
Forestville/Mystery Cave State Park N 43 º 38.425 W 092 º 13.110
|
||||
Big Stone Lake State Park N 45 º 23.126 W 096 º 32.099
|
||||
Lake Vermilion-Soudan Underground Mine State Park N 47 º 49.197 W 092 º 14.320
|
||||
Red River State Recreation Area N 47 º 55.743 W 097 º 01.723
|
||||
Great River Bluffs State Park N 46 º 51.919 W 096 º 28.031
|
||||
Crow Wing State Park N 46 º 16.389 W 094 º 19.972
|
||||
Beaver Creek Valley State Park N 43 º 38.571 W 091 º 34.872
|
||||
Shooting Star State Trail N 43 º 31.547 W 092 º 30.986
|
||||
Glacial Lakes State Park N 45 º 32.438 W 095 º 31.430
|
||||
Flandrau State Park N 44 º 17.596 W 094 º 28.065
|
||||
Lac Qui Parle State Park N 45 º 02.620 W 095 º 53.025
|
||||
Wild River State Park N 45 º 32.139 W 092 º 43.947
|
||||
Lake Shetek State Park N 44 º 06.248 W 095 º 41.103
|
||||
Maplewood State Park N 46 º 32.361 W 095 º 59.151
|
||||
Old Mill State Park N 48 º 21.691 W 096 º 34.011
|
||||
Banning State Park N 46 º 09.869 W 092 º 50.373
|
||||
Jay Cooke State Park N 46 º 39.271 W 092 º 22.270
|
||||
Camden State Park N 44 º 20.787 W 095 º 55.735
|
||||
Afton State Park N 44 º 51.336 W 092 º 46.484
|
||||
Minneopa State Park N 44 º 08.879 W 094 º 05.540
|
||||
Rice Lake State Park N 44 º 05.576 W 093 º 03.849
|
||||
McCarthy Beach State Park N 47 º 40.200 W 093 º 01.830
|
||||
Whitewater State Park N 44 º 03.206 W 092 º 02.703
|
||||
Monson Lake State Park N 45 º 19.164 W 095 º 16.493
|
||||
Father Hennepin State Park N 46 º 08.614 W 093 º 28.948
|
||||
Lake Carlos State Park N 46 º 00.052 W 095 º 20.073
|
||||
Moose Lake State Park N 46 º 26.109 W 092 º 43.949
|
||||
John A. Latsch State Park N 44 º 10.310 W 091 º 50.319
|
||||
St. Croix State Park N 45 º 57.048 W 092 º 34.198
|
||||
Big Bog State Recreation Area N 48 º 10.203 W 094 º 30.901
|
||||
Garden Island State Recreation Area Alternate N 48 º 52.073 W 094 º 50.896
|
||||
William O’Brien State Park N 45 º 13.373 W 092 º 46.047
|
||||
Buffalo River State Park N 46 º 51.919 W 096 º 28.031
|
113
extras/cloak/ciphers/hashesMD5
Normal file
113
extras/cloak/ciphers/hashesMD5
Normal file
@ -0,0 +1,113 @@
|
||||
033698705E420DD71634D5C8A861DE7E
|
||||
0566F25FC73E4ACC826C84FF521EDAF7
|
||||
05D5668D5CF9A65FAABE2186C0B19001
|
||||
0991756FBCC2D438CDDD07E7BA996C4F
|
||||
0A12376A0B0A65C39299D94EB02FE799
|
||||
0A26C74B6012B5BBBF715B9327C00C44
|
||||
0BF2D9B8F392C853EE41F15006A38839
|
||||
0F5F49305B40F326674AD23AED0554BC
|
||||
0F82D00A63498CCE8982D5608B759F9E
|
||||
10515EC6CF372232E995602BB7A70046
|
||||
1080418C171BB86F202DA3EB234C74A1
|
||||
108B7B6D86873256A1958916035872E9
|
||||
10B43971A8295F3720F38FBCDD9D6AC6
|
||||
137609CBF5410CFDC487FC2118FB16AE
|
||||
13D1261EFBCEAE62EC6B65F3257769A4
|
||||
15BB21591BE151CAADCC264D3602E522
|
||||
1ACC555ADC3E731133EEAA80154BB886
|
||||
1B4E227142C24B81C9EAA61122B12CB1
|
||||
1C63129AE9DB9C60C3E8AA94D3E00495
|
||||
1D1E60D5E0B698FF150DCAB24DF184D5
|
||||
1F7A1132D93837D2A83E4CA8FABA9941
|
||||
2345F10BB948C5665EF91F6773B3E455
|
||||
236B922AEA10AF085C5206E4D5DBCC85
|
||||
26B580B0AEDE3B3E8B58BC761E09577C
|
||||
26E059C26592E4A078CCB31AFEDF213C
|
||||
26FEE1830A3552695A975E509B289F0D
|
||||
2902A7FD778812E75F953779B67BE83C
|
||||
2AAE667514F164221A71E9CEB734E31A
|
||||
2B92AD5136C0C171DF9B02A24D3D9C82
|
||||
332D114301906A70E56EDB1325B192E3
|
||||
3362E5D0E467010F8FFAFE6E079B3FCC
|
||||
35E656E1FCF2FC8FBCAC23EA148E7BD0
|
||||
3B287E2F82D9B57BD0801638A21B6EB6
|
||||
40068DCA5800AD8BC5E1EA749B5A968F
|
||||
447CC066DE9703C5AEE3FDD3AF0AD5E0
|
||||
45C311F94E075EF1F15EFBA7B5084A10
|
||||
498A8A3364A43A8E9D880E441043E33F
|
||||
4AAEA6397CFA277E4433FA325FA396F7
|
||||
4DC642D0E0881B63072691C194F99B7E
|
||||
51951570A66679F7B5C21A83E3385D13
|
||||
5263DC84FFBA8FA607754CACCE3E65FD
|
||||
57AC36ADC5258C1B8048A7D7BD966A73
|
||||
5836CAD35828419B754B684A9DA147A0
|
||||
596BFF793A503D75B68B760A9BF70AA3
|
||||
5E5B18D4681B24F342F89A19DA2D4699
|
||||
604E708741886E3D922D26CE1A7B2835
|
||||
618206DD0078A5740373C161D7570989
|
||||
64B9469496B3012D4E19F626AC068233
|
||||
64F4AE7B5A81F0EB65316410581047C0
|
||||
6676E7D0995EBD8DBD136869A9358D14
|
||||
69BDBA2238286ED674D2DBD66319B629
|
||||
69F3EEC589EFF77854287AF84E0258FE
|
||||
6FC4B922446021AD57578E4E281D7965
|
||||
722EF044BF1D7A293440B68A6E7B6721
|
||||
744CE343D3FAF9FBFA81116688714F3B
|
||||
791701316B125F94CC61F8C2D9FF9C58
|
||||
7989D7CFAF00CAB7D0B6A58324EB63E9
|
||||
7A2D09AF8F40467DDDAF0F946960ADE3
|
||||
7AD7E9A563E9F3CA7175DE3668C85654
|
||||
7BCD03390834DFF914740E27D826C2DA
|
||||
7E5FAF44E6D49A0000135A9D5D59EF76
|
||||
7EDEB90A6ED6E0141E9F28FACA7F3AF6
|
||||
8350ADB55BAA13F09BFB53B0D51CAF2D
|
||||
859C7547DF3CA77B07D4ECD3B0F42F57
|
||||
865BDF0F2727792BCD77C7BE5B36C6CA
|
||||
8745BA34F93696B1165C36A52FAC0FDF
|
||||
8904646023577F9746BADE425D317ABE
|
||||
8911BFAF73444B67B000B3D3EDB55E6D
|
||||
8A548185B6A6A873D9243072B13D04AB
|
||||
8B0EE5A501CEF4A5699FD3B2D4549E8F
|
||||
8BD2DB1BE8AABBC2CE9AE757D0302707
|
||||
939E652393234AE78B511092C5B3A0B6
|
||||
93FE91EB27123C4927105753C4DB4B7D
|
||||
9536637DF923B3AAD6DDE0A80D7CD7E4
|
||||
9684C7747527BFA45DE2D0E733058D9F
|
||||
970796E057AD9284F16AF55E19BDCE7F
|
||||
9A0711EC9F302EDE9C07731208553E69
|
||||
9FEA03AA1B4293B8566B1B5AEAE12D8F
|
||||
A304C99480E027B2D2AE5A9D10021335
|
||||
A33B929706F3280EC6D46BE67E569915
|
||||
A402080405F59AAD7E3C66B2339B1311
|
||||
A4DC1273708D83FCF39355AFA587E2EC
|
||||
A5484EEFDBC11797A293DA331B31C62B
|
||||
A59D3A8442AD87289D6891238CD9C7DD
|
||||
A8A4C199766A66EA54079F19F819EE8D
|
||||
A8EA4070D693DB509DECA6676DE675E9
|
||||
AA13ABDB56EA5FD37B133F96EB3E3B6A
|
||||
AB6A89F36224022B8A954316C55137DC
|
||||
AEBA8FB7353C9C4F9B27F015FB9DC5AD
|
||||
B13A1C9325803C9258F868EF97F04F8D
|
||||
B32FD22E4BFAD91974A40D08EBC7D8B1
|
||||
B55549D6177C833E55DFA04F6A3650DC
|
||||
B79313B4FE11BF40EA80915AD676BE5E
|
||||
B80370360E1E0D5F7BA9709B12A01DEA
|
||||
BAE0168A5446D0B00D13B5CEC4D6F905
|
||||
BBA3BAFE548581C53B933B7DCCE620AB
|
||||
C03AA55846E82AEEADF1879065BAF7ED
|
||||
C44A471BD78CC6C2FEA32B9FE028D30A
|
||||
C5B68394786DF93CF7AD7366D3D5807C
|
||||
CD00B006870EABFBB56135FFAF2AC444
|
||||
CD8032768CFBD94F5C5876BA56EB78CD
|
||||
D27E2ABDB7A8F23407B803E04EB5AD90
|
||||
DB99B1E9EE0E4BB159F9256820214634
|
||||
E0F79190404F264B77DEA125D5FC8304
|
||||
E12B91EF812074FFD54663280739B825
|
||||
F0B2231D462E970D954AA661122D1034
|
||||
F55893FDF4409E1C6C2574C8D3005A6E
|
||||
F5E852552DEB0FF9A3899938E77CCCDE
|
||||
F89684B8DD9E68E3261E617D772ECF0E
|
||||
FA767CDB99CE06491731B69DDEEFBD69
|
||||
FCC96DF2D80B43831F5926BE58F63574
|
||||
FDB8250C494E39F3820B7C81DA1418A7
|
||||
FE4CEEB01D43A6C29D8F4FE93313C6C1
|
77
extras/cloak/ciphers/ipAddressesTop100
Normal file
77
extras/cloak/ciphers/ipAddressesTop100
Normal file
@ -0,0 +1,77 @@
|
||||
198.78.201.252
|
||||
209.200.154.225
|
||||
69.171.224.11
|
||||
144.198.29.112
|
||||
69.65.13.216
|
||||
208.87.33.151
|
||||
209.31.22.39
|
||||
69.63.181.15
|
||||
69.63.187.17
|
||||
65.55.72.135
|
||||
208.94.146.80
|
||||
74.125.157.99
|
||||
69.63.181.12
|
||||
178.162.238.136
|
||||
64.208.126.67
|
||||
72.247.244.88
|
||||
69.10.25.46
|
||||
178.17.165.74
|
||||
69.63.176.13
|
||||
97.107.137.164
|
||||
131.253.13.32
|
||||
98.124.248.77
|
||||
199.59.148.10
|
||||
195.191.207.40
|
||||
194.71.107.15
|
||||
31.7.57.13
|
||||
69.63.187.18
|
||||
212.58.241.131
|
||||
208.80.152.201
|
||||
80.94.76.5
|
||||
93.158.65.211
|
||||
89.238.130.247
|
||||
173.231.140.219
|
||||
199.7.177.218
|
||||
216.239.113.172
|
||||
95.211.149.7
|
||||
174.121.194.34
|
||||
173.0.84.3
|
||||
74.125.224.72
|
||||
207.97.227.239
|
||||
95.211.143.200
|
||||
91.220.176.248
|
||||
199.59.149.230
|
||||
174.140.154.20
|
||||
74.125.65.91
|
||||
65.39.178.43
|
||||
62.149.24.66
|
||||
74.125.224.181
|
||||
69.63.181.11
|
||||
199.47.217.179
|
||||
72.233.56.138
|
||||
97.107.132.144
|
||||
84.22.170.149
|
||||
62.149.24.67
|
||||
69.174.244.50
|
||||
109.163.226.240
|
||||
23.21.142.179
|
||||
216.52.208.187
|
||||
69.63.187.19
|
||||
98.139.183.24
|
||||
76.74.254.126
|
||||
205.196.120.13
|
||||
98.137.149.56
|
||||
65.55.175.254
|
||||
199.9.249.21
|
||||
69.63.184.142
|
||||
216.52.242.86
|
||||
184.173.141.231
|
||||
208.223.219.206
|
||||
194.71.107.50
|
||||
67.201.54.151
|
||||
64.191.203.30
|
||||
174.140.154.32
|
||||
72.21.211.176
|
||||
67.21.232.223
|
||||
23.23.130.59
|
||||
69.171.234.21
|
76
extras/cloak/ciphers/pokemonGo
Normal file
76
extras/cloak/ciphers/pokemonGo
Normal file
@ -0,0 +1,76 @@
|
||||
Bellsprout
|
||||
Zubat
|
||||
Doduo
|
||||
Rhyhorn
|
||||
Dratini
|
||||
Snorlax
|
||||
Krabby
|
||||
Onix
|
||||
Ponyta
|
||||
Paras
|
||||
Lapras
|
||||
Drowzee
|
||||
Zapdos
|
||||
Diglett
|
||||
Sandshrew
|
||||
Ekans
|
||||
Lickitung
|
||||
Tangela
|
||||
Scyther
|
||||
Oddish
|
||||
Geodude
|
||||
Slowpoke
|
||||
Voltorb
|
||||
Magmar
|
||||
Pidgey
|
||||
Caterpie
|
||||
Nidoran
|
||||
Poliwag
|
||||
Shellder
|
||||
Koffing
|
||||
Seel
|
||||
Mew
|
||||
Growlithe
|
||||
Machop
|
||||
Vulpix
|
||||
Porygon
|
||||
Mankey
|
||||
Hitmonchan
|
||||
Farfetchd
|
||||
Kabuto
|
||||
Tauros
|
||||
Venonat
|
||||
Articuno
|
||||
Clefairy
|
||||
Psyduck
|
||||
Jynx
|
||||
Squirtle
|
||||
Horsea
|
||||
Jigglypuff
|
||||
Mewtwo
|
||||
Pinsir
|
||||
Hitmonlee
|
||||
Goldeen
|
||||
Kangaskhan
|
||||
Moltres
|
||||
Cubone
|
||||
Magnemite
|
||||
Staryu
|
||||
Weedle
|
||||
Charmander
|
||||
Pikachu
|
||||
Omanyte
|
||||
Tentacool
|
||||
Spearow
|
||||
Grimer
|
||||
Gastly
|
||||
Abra
|
||||
Magikarp
|
||||
Rattata
|
||||
Aerodactyl
|
||||
Bulbasaur
|
||||
Electabuzz
|
||||
Meowth
|
||||
Ditto
|
||||
Chansey
|
||||
Exeggcute
|
67
extras/cloak/ciphers/rickrollYoutube
Normal file
67
extras/cloak/ciphers/rickrollYoutube
Normal file
@ -0,0 +1,67 @@
|
||||
https://bit.ly/1bu2Ruu
|
||||
https://bit.ly/1ijxdRx
|
||||
https://bit.ly/1FQbMVt
|
||||
https://bit.ly/2nQmPXd
|
||||
https://bit.ly/2oq4DYI
|
||||
https://bit.ly/2Kb9fsx
|
||||
https://bit.ly/1f9lqAP
|
||||
https://bit.ly/IqT6zt
|
||||
https://bit.ly/2HjNryg
|
||||
https://bit.ly/2efiE68
|
||||
https://bit.ly/2geoqTg
|
||||
https://bit.ly/2xZrYlX
|
||||
https://bit.ly/29wawO1
|
||||
https://bit.ly/2IvdUsg
|
||||
https://bit.ly/2Guggqi
|
||||
https://bit.ly/1p9Gf4X
|
||||
https://bit.ly/2jQX9JX
|
||||
https://bit.ly/2KT5CbZ
|
||||
https://bit.ly/2gkkzU2
|
||||
https://bit.ly/2ItVvMx
|
||||
https://bit.ly/2I9RflR
|
||||
https://bit.ly/2FFZyE3
|
||||
https://bit.ly/2uGlEgu
|
||||
https://bit.ly/2jP0U2S
|
||||
https://bit.ly/2IvQJOs
|
||||
https://bit.ly/2lqrm1G
|
||||
https://bit.ly/R0z0jZ
|
||||
https://bit.ly/1yA76u9
|
||||
https://bit.ly/1zTtQZr
|
||||
https://bit.ly/2Iwbcmh
|
||||
https://bit.ly/2I92hnl
|
||||
https://bit.ly/2IcYpC2
|
||||
https://bit.ly/2I5fm56
|
||||
https://bit.ly/2KcvsXq
|
||||
https://bit.ly/2KRVKPD
|
||||
https://bit.ly/2jN3VjX
|
||||
https://bit.ly/2KS8mqi
|
||||
https://bit.ly/1QasgsE
|
||||
https://bit.ly/2ryu1eN
|
||||
https://bit.ly/2ff2sPq
|
||||
https://bit.ly/2I5eIVr
|
||||
https://bit.ly/2G472wA
|
||||
https://bit.ly/2rxYokQ
|
||||
https://bit.ly/2eO3vYp
|
||||
https://bit.ly/2jLbl7w
|
||||
https://bit.ly/2rxVPQq
|
||||
https://bit.ly/1UisbYb
|
||||
https://bit.ly/2ry3luH
|
||||
https://bit.ly/2G3vWNb
|
||||
https://bit.ly/1iegU5b
|
||||
https://bit.ly/2G3wnHj
|
||||
https://bit.ly/2I6dYPX
|
||||
https://bit.ly/2rxWXn8
|
||||
https://bit.ly/2wxIYCQ
|
||||
https://bit.ly/2jO8lY8
|
||||
https://bit.ly/2jQbuXg
|
||||
https://bit.ly/29yCC7s
|
||||
https://bit.ly/2KOGFyi
|
||||
https://bit.ly/2KTRv6q
|
||||
https://bit.ly/2IvLePW
|
||||
https://bit.ly/2jP6ylA
|
||||
https://bit.ly/2KcD3VQ
|
||||
https://bit.ly/1NistpZ
|
||||
https://bit.ly/1Qz4NnI
|
||||
https://bit.ly/2Ib66bT
|
||||
https://bit.ly/2Bj7825
|
||||
https://bit.ly/2rzRuLR
|
68
extras/cloak/ciphers/skiResorts
Normal file
68
extras/cloak/ciphers/skiResorts
Normal file
@ -0,0 +1,68 @@
|
||||
Niseko, Japan
|
||||
Jackson Hole, Wyoming
|
||||
Squaw Valley, California
|
||||
Kirkwood, California
|
||||
Alpine Meadows, California
|
||||
Grand Targhee Resort, Wyoming
|
||||
Red Mountain Resort, British Columbia
|
||||
Big Bear, California
|
||||
Alagna, Italy
|
||||
Grand Targhee, Wyoming
|
||||
La Hoya, Chile
|
||||
Mountain High, California
|
||||
Meribel, France
|
||||
Kitzbühel, Austria
|
||||
Breckenridge, Colorado
|
||||
Heavenly, California & Nevada
|
||||
Taos, New Mexico
|
||||
Canyons, Utah
|
||||
Murren, Switzerland
|
||||
Snowbasin, Utah
|
||||
Incline Village, Nevada
|
||||
Winter Park, Colorado
|
||||
Shiga Kogen, Japan
|
||||
Park City, Utah
|
||||
Smuggler’s Notch, Vermont
|
||||
Mt. Schweitzer, Idaho
|
||||
Bernese Oberland, Switzerland
|
||||
Sierra-at-Tahoe, California
|
||||
Aspen-Snowmass, Colorado
|
||||
Riksgransen, Sweden
|
||||
Telluride, Colorado
|
||||
Solitude, Utah
|
||||
Mammoth Mountain, California
|
||||
Wolf Creek Ski Area
|
||||
Stowe, Vermont
|
||||
Craigieburn, New Zealand
|
||||
Big Sky, Montana
|
||||
Crested Butte, Colorado
|
||||
Jay Peak, Vermont
|
||||
Tremblant, Quebec
|
||||
Verbier, Switzerland
|
||||
Cortina d’Ampezzo, Italy
|
||||
Mount Snow, Vermont
|
||||
Vail, Colorado
|
||||
Keystone, Colorado
|
||||
Sun Valley, Idaho
|
||||
Timberline, Mt Hood Oregon
|
||||
Silverton, Colorado
|
||||
Wanaka, New Zealand
|
||||
Brighton, Utah
|
||||
St. Anton, Austria
|
||||
Mt. Rose, Nevada
|
||||
Okemo Mountain Resort, Vermont
|
||||
Copper Mountain, Colorado
|
||||
Northstar, California
|
||||
Beaver Creek, Colorado
|
||||
Whistler-Blackcomb, British Columbia
|
||||
Sundance, Utah
|
||||
Nozawa Onsen, Japan
|
||||
Deer Valley, Utah
|
||||
Whiteface Mountain, New York
|
||||
Purgatory, Colorado
|
||||
Mt. Bachelor, Oregon
|
||||
Killington, Vermont
|
||||
Snowbird, Utah
|
||||
Revelstoke, British Columbia
|
||||
Treble Cone, New Zealand
|
||||
Alta, Utah
|
147
extras/cloak/ciphers/starTrek
Normal file
147
extras/cloak/ciphers/starTrek
Normal file
@ -0,0 +1,147 @@
|
||||
Ishka
|
||||
Nog
|
||||
Charles Tucker
|
||||
William Riker
|
||||
Dolim
|
||||
Lon Suder
|
||||
Brunt
|
||||
Hogan
|
||||
J. M. Colt
|
||||
Winn Adami
|
||||
Leonardo da Vinci
|
||||
Jake Sisko
|
||||
Azan
|
||||
Amanda Grayson
|
||||
Weyoun
|
||||
Ayala
|
||||
Nyota Uhura
|
||||
Tuvok
|
||||
Saavik
|
||||
Lwaxana Troi
|
||||
Gowron
|
||||
José Tyler
|
||||
Miles O'Brien
|
||||
Kashimuro Nozawa
|
||||
Soval
|
||||
William Ross
|
||||
Shakaar Edon
|
||||
Kathryn Janeway
|
||||
Jonathan Archer
|
||||
Keiko O'Brien
|
||||
Kimara Cretak
|
||||
Julian Bashir
|
||||
Dukat
|
||||
Spock
|
||||
Alexander Rozhenko
|
||||
Seska
|
||||
Evek
|
||||
Sonya Gomez
|
||||
Tora Ziyal
|
||||
Damar
|
||||
Chakotay
|
||||
Mezoti
|
||||
Hugh of Borg
|
||||
Sela
|
||||
Thy'lek Shran
|
||||
Leonard McCoy
|
||||
Michael Rostov
|
||||
Jennifer Sisko
|
||||
Janice Rand
|
||||
Daniels
|
||||
Degra
|
||||
Beverly Crusher
|
||||
Kasidy Yates
|
||||
Reginald Barclay
|
||||
The Doctor
|
||||
Kes
|
||||
Jal Culluh
|
||||
Rom
|
||||
Mallora
|
||||
Elim Garak
|
||||
Silik
|
||||
Neelix
|
||||
Michael Jonas
|
||||
Phlox
|
||||
The Borg Queen
|
||||
Benjamin Sisko
|
||||
Kurn
|
||||
Hoshi Sato
|
||||
Mot
|
||||
K'Ehleyr
|
||||
Guinan
|
||||
Erika Hernandez
|
||||
B'Etor
|
||||
Leeta
|
||||
Harry Kim
|
||||
James T. Kirk
|
||||
Joseph Sisko
|
||||
Tal Celes
|
||||
The Traveler
|
||||
Samantha Wildman
|
||||
Rebi
|
||||
Morn
|
||||
Lursa
|
||||
Luther Sloan
|
||||
Female Changeling
|
||||
Susan Nicoletti
|
||||
Naomi Wildman
|
||||
Mr. Homn
|
||||
Katherine Pulaski
|
||||
Phillip Boyce
|
||||
Ezri Dax
|
||||
Christopher Pike
|
||||
Carol Marcus
|
||||
Mora Pol
|
||||
Kira Nerys
|
||||
Vash
|
||||
T'Pol
|
||||
Hikaru Sulu
|
||||
Jean-Luc Picard
|
||||
Bareil Antos
|
||||
Wesley Crusher
|
||||
Number One
|
||||
Geordi La Forge
|
||||
Montgomery Scott
|
||||
Lore
|
||||
Garrison
|
||||
Jannar
|
||||
Ro Laren
|
||||
Zek
|
||||
Icheb
|
||||
Tomalak
|
||||
Vorik
|
||||
Elizabeth Cutler
|
||||
Maxwell Forrest
|
||||
Maihar'du
|
||||
Vic Fontaine
|
||||
Owen Paris
|
||||
Michael Eddington
|
||||
Malcolm Reed
|
||||
Li Nalas
|
||||
Pavel Chekov
|
||||
Travis Mayweather
|
||||
B'Elanna Torres
|
||||
Worf
|
||||
Tom Paris
|
||||
Sarah Sisko
|
||||
Jadzia Dax
|
||||
Mila
|
||||
Data
|
||||
Q
|
||||
Seven of Nine
|
||||
Christine Chapel
|
||||
Alyssa Ogawa
|
||||
Joseph Carey
|
||||
Molly O'Brien
|
||||
Sarek
|
||||
Martok
|
||||
J. Hayes
|
||||
Kor
|
||||
Enabran Tain
|
||||
Robin Lefler
|
||||
Deanna Troi
|
||||
Quark
|
||||
Chell
|
||||
Tasha Yar
|
||||
Opaka Sulan
|
||||
Odo
|
77
extras/cloak/ciphers/statusCodes
Normal file
77
extras/cloak/ciphers/statusCodes
Normal file
@ -0,0 +1,77 @@
|
||||
Status code: 60
|
||||
Status code: 612
|
||||
Status code: 299
|
||||
Status code: 725
|
||||
Status code: 974
|
||||
Status code: 472
|
||||
Status code: 182
|
||||
Status code: 256
|
||||
Status code: 203
|
||||
Status code: 619
|
||||
Status code: 915
|
||||
Status code: 746
|
||||
Status code: 77
|
||||
Status code: 857
|
||||
Status code: 865
|
||||
Status code: 488
|
||||
Status code: 115
|
||||
Status code: 159
|
||||
Status code: 782
|
||||
Status code: 500
|
||||
Status code: 962
|
||||
Status code: 333
|
||||
Status code: 938
|
||||
Status code: 395
|
||||
Status code: 320
|
||||
Status code: 821
|
||||
Status code: 894
|
||||
Status code: 898
|
||||
Status code: 287
|
||||
Status code: 871
|
||||
Status code: 870
|
||||
Status code: 575
|
||||
Status code: 867
|
||||
Status code: 216
|
||||
Status code: 116
|
||||
Status code: 937
|
||||
Status code: 662
|
||||
Status code: 593
|
||||
Status code: 423
|
||||
Status code: 748
|
||||
Status code: 647
|
||||
Status code: 62
|
||||
Status code: 817
|
||||
Status code: 452
|
||||
Status code: 212
|
||||
Status code: 946
|
||||
Status code: 471
|
||||
Status code: 401
|
||||
Status code: 527
|
||||
Status code: 935
|
||||
Status code: 131
|
||||
Status code: 119
|
||||
Status code: 868
|
||||
Status code: 776
|
||||
Status code: 762
|
||||
Status code: 706
|
||||
Status code: 268
|
||||
Status code: 331
|
||||
Status code: 106
|
||||
Status code: 787
|
||||
Status code: 89
|
||||
Status code: 134
|
||||
Status code: 681
|
||||
Status code: 793
|
||||
Status code: 971
|
||||
Status code: 355
|
||||
Status code: 28
|
||||
Status code: 31
|
||||
Status code: 559
|
||||
Status code: 715
|
||||
Status code: 501
|
||||
Status code: 385
|
||||
Status code: 197
|
||||
Status code: 709
|
||||
Status code: 344
|
||||
Status code: 205
|
||||
Status code: 892
|
71
extras/cloak/ciphers/topWebsites
Normal file
71
extras/cloak/ciphers/topWebsites
Normal file
@ -0,0 +1,71 @@
|
||||
office.com
|
||||
imgur.com
|
||||
microsoft.com
|
||||
outbrain.com
|
||||
amazon.com
|
||||
reddit.com
|
||||
aol.com
|
||||
netflix.com
|
||||
bankofamerica.com
|
||||
force.com
|
||||
wordpress.com
|
||||
bing.com
|
||||
foxnews.com
|
||||
wellsfargo.com
|
||||
google.com
|
||||
blogspot.com
|
||||
cnet.com
|
||||
homedepot.com
|
||||
instagram.com
|
||||
live.com
|
||||
etsy.com
|
||||
stackoverflow.com
|
||||
imdb.com
|
||||
github.com
|
||||
facebook.com
|
||||
huffingtonpost.com
|
||||
craiglist.org
|
||||
walmart.com
|
||||
diply.com
|
||||
quora.com
|
||||
wikia.com
|
||||
pinterest.com
|
||||
groupon.com
|
||||
bestbuy.com
|
||||
pandora.com
|
||||
tripadvisor.com
|
||||
msn.com
|
||||
amazonaws.com
|
||||
indeed.com
|
||||
tumblr.com
|
||||
apple.com
|
||||
xfinity.com
|
||||
comcast.net
|
||||
capitalone.com
|
||||
citi.com
|
||||
ebay.com
|
||||
go.com
|
||||
espn.go.com
|
||||
yelp.com
|
||||
zillow.com
|
||||
vice.com
|
||||
salesforce.com
|
||||
washingtonpost.com
|
||||
chase.com
|
||||
forbes.com
|
||||
buzzfeed.com
|
||||
cnn.com
|
||||
microsoftonline.com
|
||||
twitter.com
|
||||
americanexpress.com
|
||||
paypal.com
|
||||
target.com
|
||||
wikipedia.com
|
||||
nytimes.com
|
||||
dropbox.com
|
||||
weather.com
|
||||
youtube.com
|
||||
usps.com
|
||||
bbc.com
|
||||
yahoo.com
|
||||
linkedin.com
|
100
extras/cloak/ciphers/worldBeaches
Normal file
100
extras/cloak/ciphers/worldBeaches
Normal file
@ -0,0 +1,100 @@
|
||||
Balos Beach, Greece
|
||||
Oludeniz Beach, Turkey
|
||||
Hanalei Bay, Hawaii, United States
|
||||
Ffryes Beach, Antigua
|
||||
Wineglass Bay, Tasmania
|
||||
Sunrise Beach, Koh Lipe, Thailand
|
||||
Coffee Bay, Wild Coast, South Africa
|
||||
Hot Water Beach, Coromandel Peninsula, New Zealand
|
||||
Bandon, Oregon, United States
|
||||
Little Corn beaches, Nicaragua
|
||||
Lover's Beach, Baja California Sur, Mexico
|
||||
Pulau Derawan, Indonesia
|
||||
Akajima, Okinawa, Japan
|
||||
Trunk Bay, St. John, U.S. Virgin Islands
|
||||
Navagio Beach, Greece
|
||||
Flamenco Beach, Puerto Rico
|
||||
Plage de Piémanson, France
|
||||
Natadola Beach, Fiji
|
||||
Cayo Paraiso, Dominican Republic
|
||||
Unawatuna, Sri Lanka
|
||||
Los Roques, Venezuela
|
||||
Champagne Beach, Vanuatu
|
||||
Kaiteriteri Beach, Nelson, New Zealand
|
||||
Matira Beach, Bora Bora, Tahiti
|
||||
Anse de Grande Saline, St. Barths
|
||||
Puka Beach, Boracay, Philippines
|
||||
Laughing Bird Caye, Belize
|
||||
El Nido, Palawan, Philippines
|
||||
Anse Source d'Argent, La Digue, Seychelles
|
||||
Beidaihe, China
|
||||
Arashi Beach, Aruba
|
||||
An Bang Beach, Hoi An, Vietnam
|
||||
Juara Beach, Tioman Island, Malaysia
|
||||
D-Day beaches, Normandy, France
|
||||
Rarotonga, Cook Islands
|
||||
West Bay Beach, Roatan, Honduras
|
||||
Cavendish Beach, Prince Edward Island, Canada
|
||||
Ifaty Beach, Madagascar
|
||||
Grande Anse Beach, La Digue Island, Seychelles
|
||||
Diani Beach, Kenya
|
||||
Dominical Beach, Costa Rica
|
||||
Bahia Solano, Colombia
|
||||
Patnem Beach, Goa, India
|
||||
Tanjung Rhu, Langkawi, Malaysia
|
||||
Essaouira, Morocco
|
||||
Tulum, Mexico
|
||||
Belle Mare, Mauritius
|
||||
Long Beach, Phu Quoc, Vietnam
|
||||
Egremni Beach, Greece
|
||||
Bondi Beach, Sydney, Australia
|
||||
Isshiki Beach, Hayama, Japan
|
||||
Paradise Beach, Rab, Croatia
|
||||
Grace Bay, Providenciales, Turks & Caicos
|
||||
Abaka Bay, Haiti
|
||||
Warwick Long Bay, Bermuda
|
||||
Phra Nang Beach, Railay, Thailand
|
||||
Karekare, West Auckland, New Zealand
|
||||
Gardner Bay, Espanola Island, Ecuador
|
||||
Meads Bay, Anguilla
|
||||
Panama City Beach, Florida, United States
|
||||
Boulders Beach, Cape Town, South Africa
|
||||
La Concha, Spain
|
||||
Rabbit Beach, Lampedusa, Italy
|
||||
Byron Bay, Australia
|
||||
Cape Maclear, Malawi
|
||||
Southwestern Beach, Koh Rong, Cambodia
|
||||
Canggu Beach, Bali, Indonesia
|
||||
Capo Sant'Andrea, Elba, Italy
|
||||
Cabbage Beach, Paradise Island, Bahamas
|
||||
Margaret River Beach, Australia
|
||||
Crane Beach, Barbados
|
||||
Radhanagar Beach, Andaman Islands, India
|
||||
Jeffreys Bay, South Africa
|
||||
Luskentyre Beach, Scotland
|
||||
Maya Bay, Ko Phi Phi, Thailand
|
||||
Long Bay, Saint-Martin
|
||||
Portstewart Strand, Northern Ireland
|
||||
Vilanculos Beach, Mozambique
|
||||
Las Salinas, Ibiza, Spain
|
||||
Grand Anse, Grenada
|
||||
Sun Island Beach, Maldives
|
||||
Whitehaven Beach, Queensland, Australia
|
||||
Placenia Beach, Belize
|
||||
Pigeon Point, Tobago, Trinidad and Tobago
|
||||
Punalu'u, Hawaii, United States
|
||||
The Baths, Virgin Gorda, British Virgin Islands
|
||||
Porto da Barra, Salvador, Brazil
|
||||
Nungwi, Zanzibar, Tanzania
|
||||
Skagen Beach, Denmark
|
||||
Palaui Island, Cagayan Valley, Philippines
|
||||
Negril Beach, Jamaica
|
||||
Falassarna Beach, Crete, Greece
|
||||
Nihiwatu Beach, Sumba, Indonesia
|
||||
Playa Paraiso, Cayo Largo, Cuba
|
||||
Bottom Bay, Barbados
|
||||
Na'ama Bay, Sharm el Sheikh, Egypt
|
||||
Haad Rin, Ko Pha Ngan, Thailand
|
||||
Pulau Perhentian Kecil, Malaysia
|
||||
Praia do Sancho, Fernando de Noronha, Brazil
|
||||
Venice Beach, California, United States
|
100
extras/cloak/ciphers/worldFootballTeams
Normal file
100
extras/cloak/ciphers/worldFootballTeams
Normal file
@ -0,0 +1,100 @@
|
||||
Celta Vigo Spain
|
||||
Rangers Scotland
|
||||
Rosario Central Argentina
|
||||
Roma Italy
|
||||
Santos FC Brazil
|
||||
Dinamo Zagreb Croatia
|
||||
Málaga Spain
|
||||
Liverpool FC England
|
||||
FC Porto Portugal
|
||||
Sevilla Spain
|
||||
Al-Ahli Saudi Arabia
|
||||
Feyenoord Netherlands
|
||||
Saint-Étienne France
|
||||
Corinthians Brazil
|
||||
Borussia Mönchengladbach Germany
|
||||
Sport Recife Brazil
|
||||
Everton FC England
|
||||
Lyon France
|
||||
Sassuolo Italy
|
||||
Schalke 04 Germany
|
||||
Internacional Brazil
|
||||
Ajax Netherlands
|
||||
Valencia Spain
|
||||
Lille France
|
||||
Villarreal Spain
|
||||
Real Sociedad Spain
|
||||
Levadia Tallinn Estonia
|
||||
Leicester City England
|
||||
Nice France
|
||||
Flora Tallinn Estonia
|
||||
Ludogorets Razgrad Bulgaria
|
||||
Atlético Madrid Spain
|
||||
BATE Borisov Belarus
|
||||
Club Brugge Belgium
|
||||
Köln Germany
|
||||
Arsenal England
|
||||
APOEL Nicosia Cyprus
|
||||
Anderlecht Belgium
|
||||
São Paulo Brazil
|
||||
Salzburg Austria
|
||||
Dynamo Kyiv Ukraine
|
||||
América Mexico
|
||||
Maribor Slovenia
|
||||
PSV Eindhoven Netherlands
|
||||
Barcelona Spain
|
||||
Monaco France
|
||||
West Ham United England
|
||||
Wolfsburg Germany
|
||||
SSC Napoli Italy
|
||||
Guangzhou Evergrande China PR
|
||||
Paris Saint Germain France
|
||||
Crvena Zvezda Serbia
|
||||
Fenerbahçe Turkey
|
||||
Boca Juniors Argentina
|
||||
FC Sheriff Moldova
|
||||
CSKA Moskva Russia
|
||||
Manchester United England
|
||||
AZ Alkmaar Netherlands
|
||||
Lazio Italy
|
||||
Inter Milan Italy
|
||||
Zenit St. Petersburg Russia
|
||||
Benfica Portugal
|
||||
Basel Switzerland
|
||||
Tottenham Hotspur England
|
||||
Bayer Leverkusen Germany
|
||||
Estudiantes Argentina
|
||||
Sporting Portugal
|
||||
Augsburg Germany
|
||||
Swansea City England
|
||||
Genoa Italy
|
||||
Celtic Scotland
|
||||
Racing Club Argentina
|
||||
Olympiakos Greece
|
||||
Juventus Italy
|
||||
Grêmio Brazil
|
||||
Mainz 05 Germany
|
||||
Sparta Prague Czech Republic
|
||||
Nomme JK Kalju Estonia
|
||||
The New Saints Wales
|
||||
Fiorentina Italy
|
||||
Borussia Dortmund Germany
|
||||
Dnipro Dnipropetrovsk Ukraine
|
||||
Beşiktaş Turkey
|
||||
Olympique Marseille France
|
||||
Atlético Mineiro Brazil
|
||||
Manchester City England
|
||||
Athletic Bilbao Spain
|
||||
Viktoria Plzeň Czech Republic
|
||||
FC Krasnodar Russia
|
||||
AC Milan Italy
|
||||
Southampton England
|
||||
Chelsea England
|
||||
San Lorenzo Argentina
|
||||
Independiente Argentina
|
||||
Atlético Nacional Colombia
|
||||
Lanús Argentina
|
||||
Real Madrid Spain
|
||||
Cruzeiro Brazil
|
||||
Bayern München Germany
|
||||
Shakhtar Donetsk Ukraine
|
111
extras/cloak/cloakify.py
Normal file
111
extras/cloak/cloakify.py
Normal file
@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Filename: cloakify.py
|
||||
#
|
||||
# Version: 1.1.0
|
||||
#
|
||||
# Author: Joe Gervais (TryCatchHCF)
|
||||
#
|
||||
# Summary: Exfiltration toolset (see decloakify.py) that transforms any filetype (binaries,
|
||||
# archives, images, etc.) into lists of words / phrases / Unicode to ease exfiltration of
|
||||
# data across monitored networks, hiding the data in plain sight. Also facilitates social
|
||||
# engineering attacks against human analysts and their workflows. Bonus Feature: Defeats
|
||||
# signature-based malware detection tools (cloak your other tools during an engagement).
|
||||
#
|
||||
# Used by cloakifyFactory.py, can be used as a standalone script as well (example below).
|
||||
#
|
||||
# Description: Base64-encodes the given payload and translates the output using a list
|
||||
# of words/phrases/Unicode provided in the cipher. This is NOT a secure encryption tool,
|
||||
# the output is vulnerable to frequency analysis attacks. Use the Noise Generator scripts
|
||||
# to add entropy to your cloaked file. You should encrypt the file before cloaking if
|
||||
# secrecy is needed.
|
||||
#
|
||||
# Prepackaged ciphers include: lists of desserts in English, Arabic, Thai, Russian,
|
||||
# Hindi, Chinese, Persian, and Muppet (Swedish Chef); PokemonGo creatures; Top 100 IP
|
||||
# Addresses; Top Websites; GeoCoords of World Capitols; MD5 Password Hashes; An Emoji
|
||||
# cipher; Star Trek characters; Geocaching Locations; Amphibians (Scientific Names);
|
||||
# evadeAV cipher (simple cipher that minimizes size of the resulting obfuscated data).
|
||||
#
|
||||
# To create your own cipher:
|
||||
#
|
||||
# - Generate a list of at least 66 unique words (Unicode-16 accepted)
|
||||
# - Remove all duplicate entries and blank lines
|
||||
# - Randomize the list (see 'randomizeCipherExample.txt' in Cloakify directory)
|
||||
# - Provide the file as the cipher argument to the script.
|
||||
# - ProTip: Place your cipher in the "ciphers/" directory and cloakifyFactory
|
||||
# will pick it up automatically as a new cipher
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# $ ./cloakify.py payload.txt ciphers/desserts > exfiltrate.txt
|
||||
#
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
array64 = list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/+=")
|
||||
|
||||
def Cloakify(payloadPath:str, cipherPath:str, outputPath:str="", password:str=None):
|
||||
"""Payload file's binary contents will be read and converted into base64.
|
||||
Cipher file will be read into a list that will be used for the payload's obfuscation.
|
||||
If an output path is defined the obfuscated content will be written to that otherwise,
|
||||
it will print it out to the console.
|
||||
|
||||
Args:
|
||||
payloadPath (str): Path to the file that will be encoded
|
||||
cipherPath (str): Path to the file used as the base64 cipher
|
||||
outputPath (str): Path to write out the obfuscated payload
|
||||
"""
|
||||
|
||||
try:
|
||||
with open(payloadPath, 'rb') as payloadFile:
|
||||
payloadRaw = payloadFile.read()
|
||||
payloadB64 = base64.encodebytes(payloadRaw)
|
||||
payloadB64 = payloadB64.decode("ascii").replace("\n", "")
|
||||
except Exception as e:
|
||||
print("Error reading payload file {}: {}".format(payloadPath, e))
|
||||
|
||||
payloadOrdering = None
|
||||
if password:
|
||||
random.seed(password)
|
||||
# Get a list of each line number in the cloaked file
|
||||
payloadOrdering = [i for i in range(len(payloadB64))]
|
||||
# Shuffle the order of the lines
|
||||
random.shuffle(payloadOrdering)
|
||||
|
||||
try:
|
||||
with open(cipherPath, encoding="utf-8") as file:
|
||||
cipherArray = file.readlines()
|
||||
except Exception as e:
|
||||
print("Error reading cipher file {}: {}".format(cipherPath, e))
|
||||
|
||||
if outputPath:
|
||||
try:
|
||||
with open(outputPath, "w+", encoding="utf-8") as outFile:
|
||||
if payloadOrdering:
|
||||
# Iterate through the randomized line order and write each line to the file
|
||||
for randomLoc in payloadOrdering:
|
||||
outFile.write(cipherArray[array64.index(payloadB64[randomLoc])])
|
||||
else:
|
||||
for char in payloadB64:
|
||||
outFile.write(cipherArray[array64.index(char)])
|
||||
except Exception as e:
|
||||
print("Error writing to output file {}: {}".format(outputPath, e))
|
||||
|
||||
else:
|
||||
for char in payloadB64:
|
||||
print(cipherArray[array64.index(char)].strip())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Transform file into obfuscated text file.')
|
||||
parser.add_argument('-i', "--input", type=str, help='Payload File Path', required=True)
|
||||
parser.add_argument('-c', "--cipher", type=str, help='Cipher File Path', required=True)
|
||||
parser.add_argument('-o', "--output", type=str, help='Output File Path', default="")
|
||||
parser.add_argument('-p', "--password", type=str, help='Password', default=None)
|
||||
args = parser.parse_args()
|
||||
|
||||
Cloakify(args.input, args.cipher, args.output, args.password)
|
84
extras/cloak/decloakify.py
Normal file
84
extras/cloak/decloakify.py
Normal file
@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Filename: decloakify.py
|
||||
#
|
||||
# Author: Joe Gervais (TryCatchHCF)
|
||||
#
|
||||
# Summary: Exfiltration toolset (see cloakify.py) that transforms data into lists
|
||||
# of words / phrases / Unicode to ease exfiltration of data across monitored networks,
|
||||
# essentially hiding the data in plain sight, and facilitate social engineering attacks
|
||||
# against human analysts and their workflows. Bonus Feature: Defeats signature-based
|
||||
# malware detection tools (cloak your other tools).
|
||||
#
|
||||
# Used by cloakifyFactory.py, can be used as a standalone script as well (example below).
|
||||
#
|
||||
# Description: Decodes the output of cloakify.py into its underlying Base64 format,
|
||||
# then does Base64 decoding to unpack the cloaked payload file. Requires the use of the
|
||||
# same cipher that was used to cloak the file prior to exfitration, of course.
|
||||
#
|
||||
# Prepackaged ciphers include: lists of desserts in English, Arabic, Thai, Russian,
|
||||
# Hindi, Chinese, Persian, and Muppet (Swedish Chef); Top 100 IP Addresses; GeoCoords of
|
||||
# World Capitols; MD5 Password Hashes; An Emoji cipher; Star Trek characters; Geocaching
|
||||
# Locations; Amphibians (Scientific Names); and evadeAV cipher, a simple cipher that
|
||||
# minimizes the size of the resulting obfuscated data.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# $ ./decloakify.py cloakedPayload.txt ciphers/desserts.ciph
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import random
|
||||
import sys
|
||||
|
||||
array64 = list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/+=")
|
||||
|
||||
def Decloakify(cloakedPath:str, cipherPath:str, outputPath:str="", password:str=""):
|
||||
"""Cipher file will be read into a list that will be used for the payload's deobfuscation.
|
||||
Cloaked file's contents will be read in line by line mapping the line to a base64 character.
|
||||
If an output path is defined the base64 contents will be decoded and written to the output
|
||||
file otherwise it will be written to the console.
|
||||
|
||||
Args:
|
||||
cloakedPath (str): Path to the file that is encoded
|
||||
cipherPath (str): Path to the file used as the base64 cipher
|
||||
outputPath (str): Path to write out the decoded
|
||||
"""
|
||||
with open(cipherPath, encoding="utf-8") as file:
|
||||
arrayCipher = file.readlines()
|
||||
|
||||
clear64 = ""
|
||||
with open(cloakedPath, encoding="utf-8") as file:
|
||||
if password:
|
||||
random.seed(password)
|
||||
lines = file.readlines()
|
||||
# Get a list of each line number in the cloaked file
|
||||
decodeOrdering = [i for i in range(len(lines))]
|
||||
# Shuffle the order of the lines to what they were during encoding
|
||||
random.shuffle(decodeOrdering)
|
||||
# Map the index of the original payload to the index in the cloaked file
|
||||
decodeOrdering = {k: v for v, k in enumerate(decodeOrdering)}
|
||||
# Iterate through the proper line order and reconstruct the unshuffled base64 payload
|
||||
for i in range(len(lines)):
|
||||
clear64 += array64[arrayCipher.index(lines[decodeOrdering[i]])]
|
||||
else:
|
||||
for line in file:
|
||||
clear64 += array64[arrayCipher.index(line)]
|
||||
|
||||
payload = base64.b64decode(clear64)
|
||||
if outputPath:
|
||||
with open(outputPath, "wb") as outFile:
|
||||
outFile.write(payload)
|
||||
else:
|
||||
print(payload)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Transform file into unobfuscated text file.')
|
||||
parser.add_argument('-i', "--input", type=str, help='Cloaked File Path', required=True)
|
||||
parser.add_argument('-c', "--cipher", type=str, help='Cipher File Path', required=True)
|
||||
parser.add_argument('-o', "--output", type=str, help='Output File Path', default="")
|
||||
parser.add_argument('-p', "--password", type=str, help='Password', default=None)
|
||||
args = parser.parse_args()
|
||||
|
||||
Decloakify(args.input, args.cipher, args.output, args.password)
|
33
extras/docker/Dockerfile
Normal file
33
extras/docker/Dockerfile
Normal file
@ -0,0 +1,33 @@
|
||||
##
|
||||
# gregtzar/tomb
|
||||
#
|
||||
# This creates an Ubuntu derived base image and installs the tomb library
|
||||
# along with it's dependencies.
|
||||
|
||||
FROM dyne/devuan:chimaera
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG TOMB_VERSION=2.9
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y -q --no-install-recommends\
|
||||
make \
|
||||
sudo \
|
||||
curl \
|
||||
rsync \
|
||||
zsh \
|
||||
gnupg \
|
||||
cryptsetup \
|
||||
pinentry-curses \
|
||||
file xxd \
|
||||
steghide \
|
||||
plocate \
|
||||
recoll
|
||||
|
||||
# Build and install Tomb from remote repo
|
||||
RUN curl https://files.dyne.org/tomb/releases/Tomb-$TOMB_VERSION.tar.gz -o /tmp/Tomb-$TOMB_VERSION.tar.gz && \
|
||||
cd /tmp && \
|
||||
tar -zxvf /tmp/Tomb-$TOMB_VERSION.tar.gz && \
|
||||
cd /tmp/Tomb-$TOMB_VERSION && \
|
||||
make install
|
21
extras/docker/LICENSE
Normal file
21
extras/docker/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Greg Tzar
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
166
extras/docker/README.md
Normal file
166
extras/docker/README.md
Normal file
@ -0,0 +1,166 @@
|
||||
# docker-tomb
|
||||
|
||||
A [docker](https://www.docker.com) wrapper for the the Linux-based [Tomb encryption library](https://www.dyne.org/software/tomb) aimed at enabling functional cross platform support for the [Tomb library](https://github.com/dyne/Tomb) and container format.
|
||||
|
||||
**This is a work in progress and while functional it is not yet fully stable or secure.**
|
||||
|
||||
# Requirements
|
||||
|
||||
This strategy should work on MacOS, Windows, Linux, and any host OS where Docker is available. The only requirement is that you must have Docker running on your machine. My recommendation for first time users is to install [Docker Desktop](https://www.docker.com/products/docker-desktop).
|
||||
|
||||
# Container Setup
|
||||
|
||||
You can build the container by running the following command from the root directory of this repo:
|
||||
|
||||
```bash
|
||||
docker build -t tomb .
|
||||
```
|
||||
|
||||
Although building it yourself is preferred, you could also pull the container from my [dockerhub repo](https://hub.docker.com/r/gregtzar/tomb).
|
||||
|
||||
You can confirm the setup by first opening an interactive bash prompt in the new container and from there confirm the tomb version and exit the container.
|
||||
|
||||
```bash
|
||||
docker run -it --rm tomb /bin/bash
|
||||
tomb -v
|
||||
exit
|
||||
```
|
||||
|
||||
### Security Notes
|
||||
|
||||
You will see by examining the `Dockerfile` that I am using Docker's official Ubuntu Bionic container as the base, and that the latest Tomb library is downloaded directly from the [official tomb filestore](https://files.dyne.org/tomb). The `TOMB_VERSION` arg near the top of the `Dockerfile` will allow you to configure which Tomb version you want.
|
||||
|
||||
Be aware that because of the way the filestore is currently organized, the curl path will break unless the version is set to the most current. I am filing a request with them to address this.
|
||||
|
||||
Optionally if you wanted to store the tomb code in the repo, for example inside of a `src` folder, then you could install it alternatively like this:
|
||||
|
||||
```
|
||||
ADD src/Tomb-$TOMB_VERSION.tar.gz /tmp/
|
||||
RUN cd /tmp/Tomb-$TOMB_VERSION && \
|
||||
make install
|
||||
```
|
||||
|
||||
# Container Usage
|
||||
|
||||
The thing which allows this container strategy to be really functional is the use of Docker's [bind mounts](https://docs.docker.com/storage/bind-mounts/) to give the dockerized tomb instance the ability to read an encrypted/closed tomb volume **from** the host and to then mount the decrypted/open tomb volume **back** to the host where it can be accessed as normal.
|
||||
|
||||
## Usage Examples
|
||||
|
||||
Once you understand the concept of docker bind mounts you will be able to run tomb commands from the host in any way you need. Here are a few examples to get you started.
|
||||
|
||||
### Create a Tomb Volume
|
||||
|
||||
First launch an interactive bash prompt in a temporary instance of the container, and bind-mount a working directory from the host machine where we can output the new tomb volume.
|
||||
|
||||
This will mount the `/tmp/tomb-gen` directy on the host to the location of `/tomb-gen` inside the docker container instance. **Note**: The `/tmp/tomb-gen` directory must already exist on the host.
|
||||
|
||||
```bash
|
||||
docker run -it --rm --privileged \
|
||||
--mount type=bind,source=/tmp/tomb-gen,target=/tomb-gen \
|
||||
tomb /bin/bash
|
||||
```
|
||||
|
||||
Now from the interative prompt inside the docker continer instance creating a new tomb volume is textbook. **Note**: If you get an error about swap partitions during the `forge` command, this is a host issue and not a container issue. You need to disable swapping on the host if you want to fix it, or use `-f` to forge ahead anyways.
|
||||
|
||||
```bash
|
||||
cd /tomb-gen
|
||||
tomb dig -s 100 secret.tomb
|
||||
tomb forge secret.tomb.key
|
||||
tomb lock secret.tomb -k secret.tomb.key
|
||||
```
|
||||
|
||||
Now the host `/tmp/tomb-gen` directory contains a new `secret.tomb` volume and `secret.tomb.key` key. Use `exit` to close the tomb container and the new files will remain on the host.
|
||||
|
||||
### Direct Mount a Tomb Volume
|
||||
|
||||
This example will use the volume and key we created in the previous example but can be modified to suite your needs. First, launch another interactive bash prompt in a temporary instance of the container.
|
||||
|
||||
This will mount the host `/tmp/tomb-gen` directory as well as a new `/tmp/tomb-mount` directory where the container can mount the open tomb volume back to so the host can access it.
|
||||
|
||||
```bash
|
||||
docker run -it --rm --privileged \
|
||||
--mount type=bind,source=/tmp/tomb-gen,target=/tomb-gen \
|
||||
--mount type=bind,source=/tmp/tomb-mount,target=/tomb-mount,bind-propagation=shared \
|
||||
tomb /bin/bash
|
||||
```
|
||||
|
||||
Now from the interative prompt inside the docker continer instance we can open the tomb volume as usual, referencing the tomb volume, key, and mount destinations bind-mounted to the host:
|
||||
|
||||
```bash
|
||||
tomb open /tomb-gen/secret.tomb /tomb-mount -k /tomb-gen/secret.tomb.key
|
||||
```
|
||||
|
||||
The contents of the tomb volume are now accessible via `/tmp/tomb-mount` on the host. Be sure to successfully close the tomb volume before you exit the docker container:
|
||||
|
||||
```bash
|
||||
tomb close
|
||||
```
|
||||
|
||||
### Unpack and Repack a Tomb Volume
|
||||
|
||||
This workflow was created as a workaround for the MacOS lack of support for bind propagation which prevents us from directly mounting a tomb volume back to the host OS. The workaround is to use an additional bash script layer to copy and synchronize the tomb volume contents between a bind mounted host directory and the mounted tomb volume accesible only from inside the docker container.
|
||||
|
||||
The `tomb.sh` script is desinged to run from the host and requires the following ENV VARS to be available to it:
|
||||
|
||||
* `TOMB_DOCKER_IMAGE`: The name of the docker image on the host. In the examples we named it `tomb`.
|
||||
* `TOMB_VOLUME`: The full path of the tomb volume file on the host. In the example it is `/tmp/tomb-gen/secret.tomb`.
|
||||
* `TOMB_VOLUME_KEY`: The full path of the tomb volume key file on the host. In the examples it is `/tmp/tomb-gen/secret.tomb.key`.
|
||||
* `TOMB_OUTPUT_DIR`: The full path of the directory where we will unpack the tomb volume contents to on the host. In the examples it is `/tmp/tomb-out`.
|
||||
|
||||
#### tomb.sh unpack
|
||||
|
||||
This command will launch a new docker container, open the tomb volume internally, and copy it's contents to the host `TOMB_OUTPUT_DIR` directory which it expects to be empty. It will then close the tomb volume and exit the docker container.
|
||||
|
||||
```bash
|
||||
export TOMB_DOCKER_IMAGE=tomb
|
||||
export TOMB_VOLUME=/tmp/tomb-gen/secret.tomb
|
||||
export TOMB_VOLUME_KEY=/tmp/tomb-gen/secret.tomb.key
|
||||
export TOMB_OUTPUT_DIR=/tmp/tomb-out
|
||||
./tomb.sh unpack
|
||||
```
|
||||
|
||||
If needed, the `-f` flag can be forwarded through to tomb by passing it to the `unpack` command.
|
||||
|
||||
```bash
|
||||
./tomb.sh unpack -f
|
||||
```
|
||||
|
||||
#### tomb.sh repack
|
||||
|
||||
This command will launch a new docker container, open the tomb volume internally, and copy the current contents of the host `TOMB_OUTPUT_DIR` directory back into the open tomb volume. Copying uses `rsync` with `--delete` any files which were removed from `TOMB_OUTPUT_DIR` will also be removed from the open tomb volume contents. It will then close the tomb volume, delete the contents of `TOMB_OUTPUT_DIR`, and exit the docker container. This way all changes are persisted back to the tomb volume. Each step is performed sequentially and an error will cause the entire sequence to bail, so for example if we are unable to successfully close the tomb volume the the contents of `TOMB_OUTPUT_DIR` will not be deleted.
|
||||
|
||||
```bash
|
||||
export TOMB_DOCKER_IMAGE=tomb
|
||||
export TOMB_VOLUME=/tmp/tomb-gen/secret.tomb
|
||||
export TOMB_VOLUME_KEY=/tmp/tomb-gen/secret.tomb.key
|
||||
export TOMB_OUTPUT_DIR=/tmp/tomb-out
|
||||
./tomb.sh repack
|
||||
```
|
||||
|
||||
If needed, the `-f` flag can be forwarded through to tomb by passing it to the `repack` command.
|
||||
|
||||
```bash
|
||||
./tomb.sh repack -f
|
||||
```
|
||||
|
||||
# Known Issues and Workarounds
|
||||
|
||||
## Swap partitions
|
||||
|
||||
The user may get a security error from Tomb regarding the swap partitions and is prompted to either disable them or force an override. While the swap error is reported by tomb, it actually pertains to the state of the host OS and not the container OS. So the recommended `swapoff -a` command will obviously work on a Linux host but won't work on a MacOS or Windows host. In these later cases it is up to the user to disable swapping (either temporarily or permanently) on their host os should they choose to, or use the `-f` flag with tomb.
|
||||
|
||||
## Privileged access containers
|
||||
|
||||
The docker container must be launched in privileged mode, otherwise the tomb library cannot mount loopback devices which it depends. Launching a docker container in privileged mode removes some of the container security sandboxing and grants anything in the container access to parts of your host system. Until docker can support loopback mounting for unprivileged users this may be the only option.
|
||||
|
||||
## Bind propagation in MacOS
|
||||
|
||||
MacOS does not supported bind propagation for bind mounts, which means we cannot set the `bind-propagation=shared` option on the `--mount` flag for the docker instance. So even though we can mount the tomb volume back to the bind-mounted host directory, the mount will not recurse and the directory will appear empty from the hosts point of view. I have attempted to overcome this a variety of ways including FUSE `bindfs` and symlinks and cannot find a way to expose the mounted tomb volume directory back to the host of MacOS. As a workaround I created the `tomb unpack` and `tomb repack` commands which use `rsync` to recursively copy the contents between the tomb volume mounted inside the docker container and the bind-mounted directory from the host.
|
||||
|
||||
## Loop device mount ghost
|
||||
|
||||
If the docker container instance is shut down before the tomb volume is successfully closed then the the mounted volume and it's contents may remain attached and available from the host. Obviously any changes made to the contents at this point will not be persisted back to the tomb volume. The ghosted device mount and it's contents will disappear the host system is restarted or the node is manually cleaned up (which I don't know how to do properly), and you will be able to mount the real tomb volume again.
|
||||
|
||||
## Filesystem permissions
|
||||
|
||||
Since the docker container needs to run as root, anything it creates will have root permissions and may not be accessible from the host user without additional privileges.
|
121
extras/docker/tomb.sh
Executable file
121
extras/docker/tomb.sh
Executable file
@ -0,0 +1,121 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
function log_info(){
|
||||
local msg=$1
|
||||
printf "INFO: ${msg}\n"
|
||||
}
|
||||
|
||||
function log_error(){
|
||||
local msg=$1
|
||||
printf "ERROR: ${msg}\n"
|
||||
}
|
||||
|
||||
# Check & Validate Required ENV VARS
|
||||
|
||||
##
|
||||
# TOMB_DOCKER_IMAGE
|
||||
if [ -z "$TOMB_DOCKER_IMAGE" ]; then
|
||||
log_error "ENV VAR: TOMB_DOCKER_IMAGE is required!"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$(docker images -q $TOMB_DOCKER_IMAGE)" ]; then
|
||||
log_error "TOMB_DOCKER_IMAGE not found: $TOMB_DOCKER_IMAGE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##
|
||||
# TOMB_VOLUME
|
||||
if [ -z "$TOMB_VOLUME" ]; then
|
||||
log_error "ENV VAR: TOMB_VOLUME is required!"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$TOMB_VOLUME" ]; then
|
||||
log_error "TOMB_VOLUME not found: $TOMB_VOLUME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##
|
||||
# TOMB_VOLUME_KEY
|
||||
if [ -z "$TOMB_VOLUME_KEY" ]; then
|
||||
log_error "ENV VAR: TOMB_VOLUME_KEY is required!"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$TOMB_VOLUME_KEY" ]; then
|
||||
log_error "TOMB_VOLUME_KEY not found: $TOMB_VOLUME_KEY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##
|
||||
# TOMB_OUTPUT_DIR
|
||||
if [ -z "$TOMB_OUTPUT_DIR" ]; then
|
||||
log_error "ENV VAR: TOMB_OUTPUT_DIR is required!"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -d "$TOMB_OUTPUT_DIR" ]; then
|
||||
log_error "TOMB_OUTPUT_DIR not found: $TOMB_OUTPUT_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Internal Vars
|
||||
I_TOMB_VOLUME=/tomb/volume
|
||||
I_TOMB_VOLUME_KEY=/tomb/volume_key
|
||||
I_TOMB_OUTPUT_DIR=/tomb/output_dir # Important: This must NOT end in a slash!
|
||||
I_TOMB_MOUNT_DIR=/tomb/mount_dir # Important: This must NOT end in a slash!
|
||||
|
||||
# Parse command
|
||||
cmd=$1
|
||||
|
||||
if [ -z "$cmd" ]; then
|
||||
log_error "A valid command is required! (eg: unpack, repack)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse flags (right now there is only one possible flag so I'm being lazy about parsing it)
|
||||
flags=$2
|
||||
|
||||
force_opt=""
|
||||
if [ "$flags" = "-f" ]; then
|
||||
force_opt=$flags
|
||||
fi
|
||||
|
||||
if [ $cmd = unpack ]; then
|
||||
|
||||
if [ ! -z "$(ls -A $TOMB_OUTPUT_DIR)" ]; then
|
||||
log_error "Cannot unpack: TOMB_OUTPUT_DIR is not empty! $TOMB_OUTPUT_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker run -it --rm --privileged \
|
||||
--mount type=bind,source=${TOMB_VOLUME},target=${I_TOMB_VOLUME} \
|
||||
--mount type=bind,source=${TOMB_VOLUME_KEY},target=${I_TOMB_VOLUME_KEY} \
|
||||
--mount type=bind,source=${TOMB_OUTPUT_DIR},target=${I_TOMB_OUTPUT_DIR} \
|
||||
tomb /bin/bash -c "set -e; tomb open ${I_TOMB_VOLUME} ${I_TOMB_MOUNT_DIR} -k ${I_TOMB_VOLUME_KEY} ${force_opt}; rsync -azh --delete ${I_TOMB_MOUNT_DIR}/ ${I_TOMB_OUTPUT_DIR}; tomb close"
|
||||
|
||||
elif [ $cmd = repack ]; then
|
||||
|
||||
if [ -z "$(ls -A $TOMB_OUTPUT_DIR)" ]; then
|
||||
log_error "Cannot repack: TOMB_OUTPUT_DIR is empty! $TOMB_OUTPUT_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker run -it --rm --privileged \
|
||||
--mount type=bind,source=${TOMB_VOLUME},target=${I_TOMB_VOLUME} \
|
||||
--mount type=bind,source=${TOMB_VOLUME_KEY},target=${I_TOMB_VOLUME_KEY} \
|
||||
--mount type=bind,source=${TOMB_OUTPUT_DIR},target=${I_TOMB_OUTPUT_DIR} \
|
||||
tomb /bin/bash -c "set -e; tomb open ${I_TOMB_VOLUME} ${I_TOMB_MOUNT_DIR} -k ${I_TOMB_VOLUME_KEY} ${force_opt}; rsync -azh --delete ${I_TOMB_OUTPUT_DIR}/ ${I_TOMB_MOUNT_DIR}; tomb close; rm -rf ${I_TOMB_OUTPUT_DIR}/..?* ${I_TOMB_OUTPUT_DIR}/* ${I_TOMB_OUTPUT_DIR}/.[!.]*"
|
||||
|
||||
elif [ $cmd = drop ]; then
|
||||
|
||||
if [ -z "$(ls -A $TOMB_OUTPUT_DIR)" ]; then
|
||||
log_error "Cannot drop: TOMB_OUTPUT_DIR is empty! $TOMB_OUTPUT_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker run -it --rm --privileged \
|
||||
--mount type=bind,source=${TOMB_OUTPUT_DIR},target=${I_TOMB_OUTPUT_DIR} \
|
||||
tomb /bin/bash -c "set -e; rm -rf ${I_TOMB_OUTPUT_DIR}/..?* ${I_TOMB_OUTPUT_DIR}/* ${I_TOMB_OUTPUT_DIR}/.[!.]*"
|
||||
|
||||
else
|
||||
log_error "Invalid command: $cmd"
|
||||
fi
|
@ -4,6 +4,23 @@
|
||||
If you like to see our nifty little skull on the upper right corner of
|
||||
your desktop, then compile and install this little auxiliary program.
|
||||
|
||||
## Build
|
||||
|
||||
Make sure that Gcc, GNU Make, pkg-config, Gtk 2.0 and libnotify
|
||||
development packages are installed: in Debian and Ubuntu the packages
|
||||
are:
|
||||
|
||||
- gcc
|
||||
- make
|
||||
- pkg-config
|
||||
- libgtk2.0-dev
|
||||
- libnotify-dev
|
||||
|
||||
Then launch the `make` command which will build the `tomb-gtk-tray`
|
||||
executable one can copy to the path (for instance `~/bin`).
|
||||
|
||||
## Usage
|
||||
|
||||
Use by launching `tomb-gtk-tray` followed by the name of your tomb as
|
||||
reported by `tomb list`. For instance if your tomb is `secrets.tomb`:
|
||||
|
||||
|
@ -18,15 +18,18 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ver="0.8"
|
||||
TOMBPATH="/usr/local/bin/tomb" # Set this to your tomb executable's path
|
||||
KDFPATH="/usr/local/bin/" # Set this to the path of your KDF binaries (if you're using them)
|
||||
# {{{ SETTINGS
|
||||
ver="0.9.1"
|
||||
KDFPATH="/usr/libexec/tomb" # Path of your KDF binaries (if you're using them).
|
||||
SWAPOFF="false" # Set to "true" to swapoff, or "false" to use -f (force) flag.
|
||||
# The ones below should not need changing
|
||||
TOMBPATH="$(which tomb)" # Tomb executable's path
|
||||
HEXENC="$KDFPATH/tomb-kdb-hexencode"
|
||||
GENSALT="$KDFPATH/tomb-kdb-pbkdf2-gensalt"
|
||||
GETITER="$KDFPATH/tomb-kdb-pbkdf2-getiter"
|
||||
PBKDF="$KDFPATH/tomb-kdb-pbkdf2"
|
||||
_DD=/bin/dd
|
||||
_DD="$(which dd)"
|
||||
# }}}
|
||||
|
||||
# {{{ monmort icon
|
||||
MONMORT="/tmp/monmort.png"
|
||||
@ -41,38 +44,23 @@ b2RpZnkAMjAxMS0wMS0xMlQwOTozNDoyNCswMTowMNKiZVMAAAAASUVORK5CYII="
|
||||
echo -e "$ICONB64" | base64 --decode > $MONMORT
|
||||
# }}}
|
||||
|
||||
# {{{ sudo functions
|
||||
function _sudo {
|
||||
sudoassword=$(ask_password "Insert sudo password for user $USER")
|
||||
echo -e "$sudoassword\n" | sudo -S -v
|
||||
_sudowrong
|
||||
}
|
||||
|
||||
function _sudowrong {
|
||||
[[ $? = 0 ]] || {
|
||||
sudoassword=$(ask_password "Wrong password. Insert sudo password for user $USER")
|
||||
echo -e "$sudoassword\n" | sudo -S -v
|
||||
_sudowrong
|
||||
}
|
||||
}
|
||||
# }}}
|
||||
|
||||
# {{{ Zenity dialogs
|
||||
Icon="--window-icon="$MONMORT""
|
||||
function _zenques {
|
||||
zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--question \
|
||||
--text="$1"
|
||||
}
|
||||
function _fsel {
|
||||
zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--file-selection \
|
||||
--title="$1"
|
||||
}
|
||||
function _fsave {
|
||||
zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--file-selection \
|
||||
--save \
|
||||
--title="$1" \
|
||||
@ -80,10 +68,10 @@ function _fsave {
|
||||
}
|
||||
function _zenwarn {
|
||||
zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--warning \
|
||||
--title="$1" \
|
||||
--text="$2"
|
||||
--title="Warning" \
|
||||
--text="$1"
|
||||
}
|
||||
function _info {
|
||||
which notify-send > /dev/null
|
||||
@ -95,28 +83,28 @@ function _info {
|
||||
}
|
||||
function _zenotif {
|
||||
zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--notification \
|
||||
--title="$1" \
|
||||
--text="$2"
|
||||
}
|
||||
function _zeninfo {
|
||||
zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--info \
|
||||
--title="$1" \
|
||||
--text="$2"
|
||||
}
|
||||
function _zenerr {
|
||||
zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--error \
|
||||
--title="$1" \
|
||||
--text="$2"
|
||||
}
|
||||
function _zenprog {
|
||||
zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--progress \
|
||||
--auto-close \
|
||||
--pulsate \
|
||||
@ -125,7 +113,7 @@ function _zenprog {
|
||||
}
|
||||
function _zenprognc {
|
||||
zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--progress \
|
||||
--auto-close \
|
||||
--no-cancel \
|
||||
@ -135,7 +123,7 @@ function _zenprognc {
|
||||
}
|
||||
function _zenentry {
|
||||
zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--entry \
|
||||
--title="$1" \
|
||||
--text="$2" \
|
||||
@ -143,166 +131,6 @@ function _zenentry {
|
||||
}
|
||||
# }}}
|
||||
|
||||
# {{{ Some pinentry code shamelessly stolen from tomb
|
||||
# Ask user for a password
|
||||
# Wraps around the pinentry command, from the GnuPG project, as it
|
||||
# provides better security and conveniently use the right toolkit.
|
||||
ask_password() {
|
||||
local description="$1"
|
||||
local title="${2:-Enter tomb password.}"
|
||||
local output
|
||||
local password
|
||||
local gtkrc
|
||||
local theme
|
||||
|
||||
# Distributions have broken wrappers for pinentry: they do
|
||||
# implement fallback, but they disrupt the output somehow. We are
|
||||
# better off relying on less intermediaries, so we implement our
|
||||
# own fallback mechanisms. Pinentry supported: curses, gtk-2, qt4
|
||||
# and x11.
|
||||
|
||||
# make sure LANG is set, default to C
|
||||
LANG=${LANG:-C}
|
||||
|
||||
_verbose "asking password with tty=$TTY lc-ctype=$LANG"
|
||||
|
||||
if [[ "$DISPLAY" = "" ]]; then
|
||||
|
||||
if _is_found "pinentry-curses"; then
|
||||
_verbose "using pinentry-curses"
|
||||
output=`cat <<EOF | pinentry-curses
|
||||
OPTION ttyname=$TTY
|
||||
OPTION lc-ctype=$LANG
|
||||
SETTITLE $title
|
||||
SETDESC $description
|
||||
SETPROMPT Password:
|
||||
GETPIN
|
||||
EOF`
|
||||
else
|
||||
_failure "Cannot find pinentry-curses and no DISPLAY detected."
|
||||
fi
|
||||
|
||||
else # a DISPLAY is found to be active
|
||||
|
||||
# customized gtk2 dialog with a skull (if extras are installed)
|
||||
if _is_found "pinentry-gtk-2"; then
|
||||
_verbose "using pinentry-gtk2"
|
||||
|
||||
gtkrc=""
|
||||
theme=/share/themes/tomb/gtk-2.0-key/gtkrc
|
||||
for i in /usr/local /usr; do
|
||||
[[ -r $i/$theme ]] && {
|
||||
gtkrc="$i/$theme"
|
||||
break
|
||||
}
|
||||
done
|
||||
[[ "$gtkrc" = "" ]] || {
|
||||
gtkrc_old="$GTK2_RC_FILES"
|
||||
export GTK2_RC_FILES="$gtkrc"
|
||||
}
|
||||
output=`cat <<EOF | pinentry-gtk-2
|
||||
OPTION ttyname=$TTY
|
||||
OPTION lc-ctype=$LANG
|
||||
SETTITLE $title
|
||||
SETDESC $description
|
||||
SETPROMPT Password:
|
||||
GETPIN
|
||||
EOF`
|
||||
[[ "$gtkrc" = "" ]] || export GTK2_RC_FILES="$gtkrc_old"
|
||||
|
||||
# TODO QT4 customization of dialog
|
||||
elif _is_found "pinentry-qt4"; then
|
||||
_verbose "using pinentry-qt4"
|
||||
|
||||
output=`cat <<EOF | pinentry-qt4
|
||||
OPTION ttyname=$TTY
|
||||
OPTION lc-ctype=$LANG
|
||||
SETTITLE $title
|
||||
SETDESC $description
|
||||
SETPROMPT Password:
|
||||
GETPIN
|
||||
EOF`
|
||||
|
||||
# TODO X11 customization of dialog
|
||||
elif _is_found "pinentry-x11"; then
|
||||
_verbose "using pinentry-x11"
|
||||
|
||||
output=`cat <<EOF | pinentry-x11
|
||||
OPTION ttyname=$TTY
|
||||
OPTION lc-ctype=$LANG
|
||||
SETTITLE $title
|
||||
SETDESC $description
|
||||
SETPROMPT Password:
|
||||
GETPIN
|
||||
EOF`
|
||||
|
||||
else
|
||||
|
||||
if _is_found "pinentry-curses"; then
|
||||
_verbose "using pinentry-curses"
|
||||
|
||||
_warning "Detected DISPLAY, but only pinentry-curses is found."
|
||||
output=`cat <<EOF | pinentry-curses
|
||||
OPTION ttyname=$TTY
|
||||
OPTION lc-ctype=$LANG
|
||||
SETTITLE $title
|
||||
SETDESC $description
|
||||
SETPROMPT Password:
|
||||
GETPIN
|
||||
EOF`
|
||||
else
|
||||
_failure "Cannot find any pinentry: impossible to ask for password."
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
fi # end of DISPLAY block
|
||||
|
||||
# parse the pinentry output
|
||||
for i in ${(f)output}; do
|
||||
[[ "$i" =~ "^ERR.*" ]] && {
|
||||
_warning "Pinentry error: ::1 error::" ${i[(w)3]}
|
||||
print "canceled"
|
||||
return 1 }
|
||||
|
||||
# here the password is found
|
||||
[[ "$i" =~ "^D .*" ]] && password="${i##D }"
|
||||
done
|
||||
|
||||
[[ "$password" = "" ]] && {
|
||||
_warning "Empty password"
|
||||
print "empty"
|
||||
return 1 }
|
||||
|
||||
print "$password"
|
||||
return 0
|
||||
}
|
||||
|
||||
_is_found() {
|
||||
# returns 0 if binary is found in path
|
||||
[[ "$1" = "" ]] && return 1
|
||||
command -v "$1" 1>/dev/null 2>/dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
function _warning no() {
|
||||
option_is_set -q || _msg warning $@
|
||||
return 1
|
||||
}
|
||||
|
||||
function _verbose xxx() {
|
||||
option_is_set -D && _msg verbose $@
|
||||
return 0
|
||||
}
|
||||
|
||||
function _failure die() {
|
||||
typeset -i exitcode=${exitv:-1}
|
||||
option_is_set -q || _msg failure $@
|
||||
# be sure we forget the secrets we were told
|
||||
exit $exitcode
|
||||
}
|
||||
# }}}
|
||||
|
||||
# {{{ _clean - Clean function, removes sensitive stuff from memory
|
||||
function _clean {
|
||||
unset $?
|
||||
@ -315,7 +143,6 @@ function _clean {
|
||||
tombname="$rr"; unset tombname
|
||||
tombsize="$rr"; unset tombsize
|
||||
keyfile="$rr"; unset keyfile
|
||||
sudoassword="$rr"; unset sudoassword
|
||||
tombtmp="/tmp/tombtmp"
|
||||
if [ -f $tombtmp ]; then
|
||||
dd if=/dev/urandom of=$tombtmp bs=800 count=1
|
||||
@ -331,10 +158,10 @@ function _clean {
|
||||
function _main {
|
||||
_clean
|
||||
cmnd=`zenity \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--title="gtomb" \
|
||||
--width=640 \
|
||||
--height=420 \
|
||||
--width=400 \
|
||||
--height=445 \
|
||||
--list \
|
||||
--hide-header \
|
||||
--text="gtomb v$ver\nThe GUI wrapper for Tomb, the crypto undertaker." \
|
||||
@ -356,6 +183,10 @@ function _main {
|
||||
"engrave" "Generates a QR code of a key to be saved on paper" \
|
||||
"bury" "Hide a key inside a JPEG image" \
|
||||
"exhume" "Extract a key from a JPEG image"`
|
||||
if [[ "$?" = 1 && $SWAPOFF = "true" ]]; then
|
||||
zenity --password --title="sudo swapon -a" | sudo swapon -a
|
||||
unset $?
|
||||
fi
|
||||
eval "_$cmnd"
|
||||
}
|
||||
# }}}
|
||||
@ -387,7 +218,7 @@ function _dig {
|
||||
exec _main
|
||||
fi
|
||||
|
||||
[[ $res = 0 ]] || { _zenwarn "Warning" "Tomb digging canceled." ; exec _main }
|
||||
[[ $res = 0 ]] || { _zenwarn "Tomb digging cancelled." ; exec _main }
|
||||
|
||||
"$TOMBPATH" dig -s "$tombsize" "$tombname" | \
|
||||
_zenprog "Digging new tomb" "Please wait while your tomb is being dug..." &
|
||||
@ -401,11 +232,13 @@ function _dig {
|
||||
|
||||
[[ -n "$PID_DD" && -z "$PID_ZEN" ]] && {
|
||||
kill -9 $PID_DD
|
||||
_zenwarn "Warning" "Tomb digging cancelled."
|
||||
_zenwarn "Tomb digging cancelled."
|
||||
rm -f "$tombname"
|
||||
exec _main
|
||||
}
|
||||
|
||||
wait
|
||||
|
||||
_info "Success" "Your tomb has been dug in $tombname"
|
||||
exec _main
|
||||
}
|
||||
@ -420,15 +253,15 @@ function _forge {
|
||||
_zenerr "Error" "This key already exists. I am not overwriting."
|
||||
exec _main
|
||||
elif [[ -z $keyfile ]]; then
|
||||
_info "gtomb" "Canceled"
|
||||
_info "gtomb" "Cancelled"
|
||||
exec _main
|
||||
fi
|
||||
|
||||
kdf=""
|
||||
kdfiter=""
|
||||
if [[ -x $HEXENC ]] && [[ -x $GENSALT ]] && [[ -x $GETITER ]] && [[ -x $PBKDF ]]; then
|
||||
if [[ -x $GENSALT ]] && [[ -x $GETITER ]] && [[ -x $PBKDF ]]; then
|
||||
_zenques "Do you want to use KDF? (Generates passwords armored against dictionary attacks)"
|
||||
[[ $? == "0" ]] && {
|
||||
if [[ $? == "0" ]]; then
|
||||
kdf="--kdf"
|
||||
kdfiter=`_zenentry "Iterations" "Enter the delay (itertime) in seconds for each time \n\
|
||||
this key is used:" "2"`
|
||||
@ -438,17 +271,17 @@ this key is used:" "2"`
|
||||
_zenerr "Error" "Please choose a valid number."
|
||||
exec _main
|
||||
elif [[ -z $kdfiter ]]; then
|
||||
_info "gtomb" "Canceled"
|
||||
_info "gtomb" "Cancelled"
|
||||
exec _main
|
||||
fi
|
||||
}
|
||||
fi
|
||||
else
|
||||
_zenotif "gtomb" "KDF binaries not found."
|
||||
fi
|
||||
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
"$TOMBPATH" forge "$keyfile" "$kdf" "$kdfiter" | \
|
||||
"$TOMBPATH" forge "$keyfile" "$kdf" "$kdfiter" "$FLAG" | \
|
||||
_zenprog "Forging key" "Please wait while your key is being forged...\n\
|
||||
You can move your mouse around and use your computer to speed up the process." &
|
||||
|
||||
@ -460,11 +293,13 @@ You can move your mouse around and use your computer to speed up the process." &
|
||||
done
|
||||
[[ -n "$PID_DD" && -z "$PID_ZEN" ]] && {
|
||||
kill -9 $PID_DD
|
||||
_zenwarn "Warning" "Forging cancelled."
|
||||
_zenwarn "Forging cancelled."
|
||||
rm -f $keyfile
|
||||
exec _main
|
||||
}
|
||||
|
||||
wait
|
||||
|
||||
_info "Success" "Your key is now forged in $keyfile"
|
||||
exec _main
|
||||
}
|
||||
@ -480,9 +315,11 @@ function _lock {
|
||||
[[ -n $keyfile ]] || { _zenotif "gtomb" "Cancelled" ; exec _main }
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
_sudo
|
||||
"$TOMBPATH" lock "$tombname" -k "$keyfile" | \
|
||||
_zenprognc "Locking your tomb" "Please wait while your tomb is being locked..."
|
||||
|
||||
wait
|
||||
|
||||
_info "Success" "Your tomb is now locked."
|
||||
exec _main
|
||||
}
|
||||
@ -496,8 +333,10 @@ function _open {
|
||||
keyfile=`_fsel "Choose the key for your tomb"`
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
_sudo
|
||||
"$TOMBPATH" open "$tombname" -k "$keyfile"
|
||||
"$TOMBPATH" open "$tombname" -k "$keyfile" "$FLAG"
|
||||
|
||||
wait
|
||||
|
||||
_info "Success" "Your tomb is now open."
|
||||
exec _main
|
||||
}
|
||||
@ -511,12 +350,12 @@ function _list {
|
||||
sed 's/.*\/\([^\/]*\)$/\1\n &/' | \
|
||||
zenity \
|
||||
--title="Currently open tombs" \
|
||||
--window-icon="$MONMORT" \
|
||||
--width=640 --height=380 --list \
|
||||
$Icon \
|
||||
--width=400 --height=380 --list \
|
||||
--separator=" & " \
|
||||
--text="Here are your open tombs" \
|
||||
--column=Tomb \
|
||||
--column=Path `
|
||||
--column="Tomb" \
|
||||
--column="Path" `
|
||||
|
||||
tombname=`echo "$tombname" | cut -c1-16`
|
||||
|
||||
@ -524,12 +363,12 @@ function _list {
|
||||
|
||||
listchoice=`zenity \
|
||||
--title="Choose action" \
|
||||
--window-icon="$MONMORT" \
|
||||
--width=640 --height=400 --list \
|
||||
$Icon \
|
||||
--width=400 --height=380 --list \
|
||||
--separator=" & " \
|
||||
--text="What do you want to do with this tomb?" \
|
||||
--column=Command \
|
||||
--column=Description \
|
||||
--column="Command" \
|
||||
--column="Description" \
|
||||
"disindex" "Disable indexing of this tomb." \
|
||||
"enindex" "Enable indexing of this tomb." \
|
||||
"close" "Close the selected tomb." \
|
||||
@ -541,13 +380,11 @@ function _list {
|
||||
|
||||
case $listchoice in
|
||||
close)
|
||||
_sudo
|
||||
"$TOMBPATH" close "$tombname"
|
||||
_zeninfo "Success" "Tomb closed successfully!"
|
||||
exec _main
|
||||
;;
|
||||
slam)
|
||||
_sudo
|
||||
"$TOMBPATH" slam "$tombname"
|
||||
_info "Success" "$tombname slammed successfully!"
|
||||
exec _main
|
||||
@ -602,7 +439,7 @@ function _close {
|
||||
sed 's/.*\/\([^\/]*\)$/\1\n &/' | \
|
||||
zenity \
|
||||
--title="Choose a tomb to close" \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--width=640 --height=380 --list \
|
||||
--separator=" & " \
|
||||
--column=Tomb \
|
||||
@ -610,7 +447,6 @@ function _close {
|
||||
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
_sudo
|
||||
tombname=`echo "$tombname" | cut -c1-16`
|
||||
"$TOMBPATH" close "$tombname"
|
||||
_info "Success" "Closed successfully!"
|
||||
@ -627,7 +463,7 @@ function _slam {
|
||||
sed 's/.*\/\([^\/]*\)$/\1\n &/' | \
|
||||
zenity \
|
||||
--title="Choose a tomb to slam" \
|
||||
--window-icon="$MONMORT" \
|
||||
$Icon \
|
||||
--width=640 --height=380 --list \
|
||||
--separator=" & " \
|
||||
--column=Tomb \
|
||||
@ -635,7 +471,6 @@ function _slam {
|
||||
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
_sudo
|
||||
tombname=`echo "$tombname" | cut -c1-16`
|
||||
"$TOMBPATH" slam "$tombname"
|
||||
_info "Success" "Slammed successfully!"
|
||||
@ -649,7 +484,7 @@ function _resize {
|
||||
res=$?
|
||||
_zenques "Is your tomb closed?"
|
||||
|
||||
[[ $? = 0 ]] || { _zenwarn "gtomb" "Please close the tomb before resizing." ; exec _main }
|
||||
[[ $? = 0 ]] || { _zenwarn "Please close the tomb before resizing." ; exec _main }
|
||||
|
||||
[[ $res = 0 ]] || exec _main
|
||||
|
||||
@ -670,7 +505,6 @@ function _resize {
|
||||
keyfile=`_fsel "Choose according keyfile"`
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
_sudo
|
||||
"$TOMBPATH" resize "$tombname" -s "$tombsize" -k "$keyfile" | \
|
||||
_zenprognc "Resizing tomb." "Please wait while your tomb is being resized..."
|
||||
_info "Success" "Tomb resized successfully!"
|
||||
@ -683,7 +517,7 @@ function _passwd {
|
||||
keyfile=`_fsel "Choose a keyfile"`
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
"$TOMBPATH" passwd -k "$keyfile" | \
|
||||
"$TOMBPATH" passwd -k "$keyfile" "$FLAG" | \
|
||||
_zenprognc "Changing passphrase" "Please wait while your key's passphrase is being changed..."
|
||||
|
||||
_info "Success" "$keyfile passphrase changed successfully!"
|
||||
@ -702,8 +536,7 @@ function _setkey {
|
||||
newkey=`_fsel "Choose your tomb's new keyfile"`
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
_sudo
|
||||
"$TOMBPATH" setkey -k "$newkey" "$keyfile" "$tombname" | \
|
||||
"$TOMBPATH" setkey -k "$newkey" "$keyfile" "$tombname" "$FLAG" | \
|
||||
_zenprognc "Changing key" "Please wait while your tomb's key is being changed..."
|
||||
|
||||
_info "Success" "$tombname keyfile successfully changed! Now using $newkey"
|
||||
@ -713,7 +546,7 @@ function _setkey {
|
||||
|
||||
# {{{ engrave - generate QR code of a key
|
||||
function _engrave {
|
||||
which qrencode || _zenwarn "Warning" "qrencode is not installed. Install it and try again"
|
||||
which qrencode || _zenwarn "qrencode is not installed. Install it and try again."
|
||||
keyfile=`_fsel "Choose a keyfile to engrave"`
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
@ -730,7 +563,7 @@ function _engrave {
|
||||
|
||||
# {{{ bury - hide a keyfile in a JPEG image
|
||||
function _bury {
|
||||
which steghide || _zenwarn "Warning" "steghide is not installed. Install it and try again"
|
||||
which steghide || _zenwarn "steghide is not installed. Install it and try again."
|
||||
keyfile=`_fsel "Choose keyfile"`
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
@ -745,7 +578,7 @@ function _bury {
|
||||
|
||||
# {{{ exhume - extract keyfile from JPEG
|
||||
function _exhume {
|
||||
which steghide || _zenwarn "Warning" "steghide is not installed. Install it and try again"
|
||||
which steghide || _zenwarn "steghide is not installed. Install it and try again."
|
||||
jpegfile=`_fsel "Choose JPEG file"`
|
||||
[[ $? = 0 ]] || exec _main
|
||||
|
||||
@ -760,7 +593,7 @@ function _exhume {
|
||||
|
||||
# {{{ index - index the contents of open tombs
|
||||
function _index {
|
||||
which locate || _zenwarn "Warning" "mlocate is not installed. Install it and try again"
|
||||
which locate || _zenwarn "mlocate is not installed. Install it and try again."
|
||||
"$TOMBPATH" index | _zenprognc "Indexing" "Please wait while the open tombs are being indexed..."
|
||||
_info "Success" "Tombs indexed!"
|
||||
exec _main
|
||||
@ -799,7 +632,16 @@ function _searchstring {
|
||||
function _ { _clean } # I like cleaning :)
|
||||
|
||||
[[ -x $TOMBPATH ]] || {
|
||||
_zenwarn "Warning" "Tomb binary is not executable or doesn't exist in the current path. Install it or edit the script to point to the correct path."
|
||||
_zenwarn "Tomb binary is not executable or doesn't exist in the current path. Install it or edit the script to point to the correct path."
|
||||
exit 1 }
|
||||
|
||||
if [[ $SWAPOFF = "true" ]]; then
|
||||
FLAG=""
|
||||
zenity --password --title="sudo swapoff -a" | sudo swapoff -a
|
||||
unset $?
|
||||
else
|
||||
FLAG="-f"
|
||||
fi
|
||||
|
||||
_main
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -ex
|
||||
git clone https://github.com/stef/libsphinx
|
||||
cd libsphinx
|
||||
git submodule update --init --recursive --remote
|
||||
cd src
|
||||
sed -i 's|/usr/local|/usr|' makefile
|
||||
make
|
||||
sudo make install
|
||||
ldconfig
|
||||
pip3 install pwdsphinx
|
||||
sudo mkdir -p /etc/sphinx
|
@ -2,10 +2,10 @@
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
all:
|
||||
$(CC) -O2 -o tomb-kdb-pbkdf2 pbkdf2.c -lgcrypt
|
||||
$(CC) -O2 -o tomb-kdb-pbkdf2-getiter benchmark.c -lgcrypt
|
||||
$(CC) -O2 -o tomb-kdb-pbkdf2-gensalt gen_salt.c -lgcrypt
|
||||
$(CC) -O2 -o tomb-kdb-hexencode hexencode.c
|
||||
$(CC) -O2 $(CFLAGS) -o tomb-kdb-pbkdf2 pbkdf2.c -lgcrypt
|
||||
$(CC) -O2 $(CFLAGS) -o tomb-kdb-pbkdf2-getiter benchmark.c -lgcrypt
|
||||
$(CC) -O2 $(CFLAGS) -o tomb-kdb-pbkdf2-gensalt gen_salt.c -lgcrypt
|
||||
$(CC) -O2 $(CFLAGS) -o tomb-kdb-hexencode hexencode.c
|
||||
|
||||
test:
|
||||
@echo "Running Tomb-kdb tests"
|
||||
|
@ -41,7 +41,7 @@ int main(int argc, char *argv[]) {
|
||||
} else {
|
||||
while( (read_bytes=fread(buf, sizeof(char), 2, stdin)) != 0) {
|
||||
if(read_bytes == 1) buf[1]='\0';
|
||||
sscanf(buf, "%x", &c);
|
||||
sscanf(buf, "%s", &c);
|
||||
printf("%c", c);
|
||||
}
|
||||
return 0;
|
||||
|
@ -140,18 +140,18 @@ int main(int argc, char *argv[])
|
||||
* passwords containing just a bunch of spaces are valid
|
||||
*/
|
||||
pass = calloc(buff_len, sizeof(char));
|
||||
char c = getchar();
|
||||
int c = getchar();
|
||||
while (c != EOF) {
|
||||
if (pw_len == buff_len) {
|
||||
buff_len *= 2;
|
||||
pass = realloc(pass, buff_len);
|
||||
if (!pass) {
|
||||
fprintf(stderr, "Error allocating memory");
|
||||
fprintf(stderr, "Error allocating memory\n");
|
||||
cleanup(result, result_len, pass, salt, salt_len);
|
||||
exit(3);
|
||||
}
|
||||
}
|
||||
pass[pw_len] = c;
|
||||
pass[pw_len] = (char)c;
|
||||
pw_len++;
|
||||
c = getchar();
|
||||
}
|
||||
|
46
extras/portable/GNUmakefile
Normal file
46
extras/portable/GNUmakefile
Normal file
@ -0,0 +1,46 @@
|
||||
.PHONY: test
|
||||
|
||||
system := $(shell uname -s)
|
||||
# if [ ${system} == "FreeBSD" ]; then sudo kldload fusefs; fi
|
||||
|
||||
TOMB ?= test.tomb
|
||||
|
||||
#########
|
||||
## BUILD
|
||||
#########
|
||||
test: create-open-close check-random-data
|
||||
|
||||
########
|
||||
## TEST
|
||||
########
|
||||
create-open-close:
|
||||
TOMB=${TOMB} ./test/bats/bin/bats ./test/create_open_close.bats
|
||||
chmod a+r ${TOMB}
|
||||
|
||||
# arg: TOMB='path to tomb containing random.data'
|
||||
# assumes $TOMB.hash is the pre-calculated hash on creation
|
||||
check-random-data:
|
||||
TOMB=${TOMB} ./test/bats/bin/bats test/check-random-data.bats
|
||||
|
||||
########
|
||||
## LINT
|
||||
########
|
||||
shellcheck:
|
||||
shellcheck -s sh tomb -e SC2006,SC2059,SC2034
|
||||
|
||||
########
|
||||
## DEPS
|
||||
########
|
||||
download-deps-ubuntu22:
|
||||
curl https://files.dyne.org/tomb3/third-party/veracrypt-ubuntu22-amd64 -o /usr/local/bin/veracrypt && chmod +x /usr/local/bin/veracrypt
|
||||
curl https://files.dyne.org/zenroom/nightly/zenroom-linux-amd64 -o /usr/local/bin/zenroom && chmod +x /usr/local/bin/zenroom
|
||||
|
||||
download-deps-ubuntu20:
|
||||
curl https://files.dyne.org/tomb3/third-party/veracrypt-ubuntu20-amd64 -o /usr/local/bin/veracrypt && chmod +x /usr/local/bin/veracrypt
|
||||
curl https://files.dyne.org/zenroom/nightly/zenroom-linux-amd64 -o /usr/local/bin/zenroom && chmod +x /usr/local/bin/zenroom
|
||||
|
||||
download-deps-freebsd13:
|
||||
curl https://files.dyne.org/tomb3/third-party/veracrypt-freebsd13-amd64 -o /usr/local/bin/veracrypt && chmod +x /usr/local/bin/veracrypt
|
||||
curl https://files.dyne.org/tomb3/third-party/zenroom-freebsd13-amd64 -o /usr/local/bin/zenroom && chmod +x /usr/local/bin/zenroom
|
||||
|
||||
#curl https://files.dyne.org/zenroom/nightly/zenroom-freebsd13-amd64 -o /usr/local/bin/zenroom && chmod +x /usr/local/bin/zenroom
|
69
extras/portable/README.md
Normal file
69
extras/portable/README.md
Normal file
@ -0,0 +1,69 @@
|
||||
|
||||
# Portable Tomb :: the crypto undertaker runs everywhere
|
||||
|
||||
[![continuous integration tests badge](https://github.com/dyne/tomb/actions/workflows/portable.yml/badge.svg)](https://github.com/dyne/Tomb/actions) test coverage status for portability
|
||||
|
||||
## ⚠️ WORK IN PROGRESS 🛠️
|
||||
|
||||
This is the portable version of [Tomb](https://github.com/dyne/tomb)
|
||||
|
||||
[![software by Dyne.org](https://files.dyne.org/software_by_dyne.png)](http://www.dyne.org)
|
||||
|
||||
# Purpose
|
||||
|
||||
Portable tomb achieves direct **interoperable access to tomb volumes** between:
|
||||
|
||||
- GNU base Linux (Ubuntu)
|
||||
- Busybox based Linux (Alpine)
|
||||
- MS/Windows using WSL2 (Ubuntu)
|
||||
- FreeBSD (WIP using libluksde)
|
||||
- ~~Apple/OSX using [MacFUSE](https://osxfuse.github.io/)~~
|
||||
|
||||
After some extensive testing during 2022, __adoption of Veracrypt in portable Tomb has been dropped__ because of unreliability and bad performance.
|
||||
|
||||
Portable tomb stays as an experimental branch that aims to reduce dependencies and in particular uses only the **POSIX sh interpreter**.
|
||||
|
||||
# Status
|
||||
|
||||
Portable tomb development is in progress and tracked via issues and the [portable milestone](https://github.com/dyne/Tomb/milestone/9).
|
||||
|
||||
## Features
|
||||
|
||||
The following features will be implemented where possible:
|
||||
|
||||
- mount bind (Linux only)
|
||||
- ps / slam
|
||||
- resize (pending investigation)
|
||||
- index & search ([recoll based](https://github.com/dyne/Tomb/issues/211))
|
||||
- bury / exhume
|
||||
|
||||
## Dependencies
|
||||
|
||||
- FreeBSD: `fusefs-libs3 fusefs-lkl e2fsprogs util-linux libluksde`
|
||||
- Linux: `fuse3 util-linux`
|
||||
- crossplatform [Veracrypt binaries](https://files.dyne.org/tomb3/third-party) console-only
|
||||
|
||||
## Note on Veracrypt
|
||||
|
||||
The way upstream developers distribute Veracrypt is far from meeting our minimalist needs, but the console-only binary once installed has a few library dependencies and is all what we need.
|
||||
|
||||
I setup [my own build](https://github.com/jaromil/veracrypt) and provide binary builds of Veracrypt v1.25.9 for download on Tomb's file repository for testing purposes.
|
||||
|
||||
# Disclaimer
|
||||
|
||||
Tomb is Copyright (C) 2007-2023 by the Dyne.org Foundation and
|
||||
developed by [Jaromil](https://github.com/jaromil).
|
||||
|
||||
This source code is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This source code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Please refer
|
||||
to the GNU Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Public License along with
|
||||
this source code; if not, write to: Free Software Foundation, Inc.,
|
||||
675 Mass Ave, Cambridge, MA 02139, USA.
|
97
extras/portable/gh-ci-portable.yml
Normal file
97
extras/portable/gh-ci-portable.yml
Normal file
@ -0,0 +1,97 @@
|
||||
name: ☠️ Portable tomb
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'extras/portable/**'
|
||||
- '.github/workflows/portable.yml'
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
paths:
|
||||
- 'extras/portable/**'
|
||||
- '.github/workflows/portable.yml'
|
||||
branches:
|
||||
- master
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
ubuntu-20:
|
||||
name: 🐧 test Ubuntu-20
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install portable tomb dependencies
|
||||
run: |
|
||||
sudo apt-get install -q -y make openssl wget fuse3 util-linux
|
||||
sudo make -C portable download-deps-ubuntu20
|
||||
- name: Run portable tomb test
|
||||
run: sudo make -C extras/portable create-open-close
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ubuntu-test.tomb
|
||||
path: extras/portable/test.tomb*
|
||||
retention-days: 1
|
||||
|
||||
freebsd:
|
||||
runs-on: macos-12
|
||||
name: 😈 test FreeBSD-13
|
||||
needs: [ubuntu-20]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download portable tomb volume built on Ubuntu
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ubuntu-test.tomb
|
||||
path: extras/portable
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v0
|
||||
with:
|
||||
usesh: true
|
||||
prepare: |
|
||||
pkg install -y sudo gmake bash fusefs-libs3 fusefs-lkl e2fsprogs wget
|
||||
wget https://files.dyne.org/tomb3/third-party/veracrypt-freebsd13-amd64
|
||||
mv veracrypt-freebsd13-amd64 /usr/bin/veracrypt
|
||||
wget https://files.dyne.org/tomb3/third-party/zenroom-freebsd13-amd64
|
||||
mv zenroom-freebsd13-amd64 /usr/bin/zenroom
|
||||
chmod a+x /usr/bin/veracrypt /usr/bin/zenroom
|
||||
kldload fusefs
|
||||
run: |
|
||||
sudo gmake -C extras/portable
|
||||
sudo gmake -C portable check-random-data
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: freebsd-test.tomb
|
||||
path: extras/portable/test.tomb*
|
||||
retention-days: 1
|
||||
|
||||
ubuntu-last-cleanup:
|
||||
name: 🎯 final Ubuntu tests and cleanup
|
||||
runs-on: ubuntu-20.04
|
||||
needs: [freebsd]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install compiler and dependencies
|
||||
run: |
|
||||
sudo apt-get install -q -y make openssl wget fuse3 util-linux
|
||||
sudo make -C extras/portable download-deps-ubuntu20
|
||||
- name: Download tomb built on FreeBSD
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: freebsd-test.tomb
|
||||
path: extras/portable
|
||||
- name: Check integrity FreeBSD->Ubuntu
|
||||
run: sudo make -C extras/portable check-random-data
|
||||
- name: delete FreeBSD tomb artifacts
|
||||
uses: geekyeggo/delete-artifact@v2
|
||||
with:
|
||||
name: freebsd-test.tomb
|
||||
- name: delete Ubuntu tomb artifacts
|
||||
uses: geekyeggo/delete-artifact@v2
|
||||
with:
|
||||
name: ubuntu-test.tomb
|
59
extras/portable/test/bats/bin/bats
Executable file
59
extras/portable/test/bats/bin/bats
Executable file
@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if command -v greadlink >/dev/null; then
|
||||
bats_readlinkf() {
|
||||
greadlink -f "$1"
|
||||
}
|
||||
else
|
||||
bats_readlinkf() {
|
||||
readlink -f "$1"
|
||||
}
|
||||
fi
|
||||
|
||||
fallback_to_readlinkf_posix() {
|
||||
bats_readlinkf() {
|
||||
[ "${1:-}" ] || return 1
|
||||
max_symlinks=40
|
||||
CDPATH='' # to avoid changing to an unexpected directory
|
||||
|
||||
target=$1
|
||||
[ -e "${target%/}" ] || target=${1%"${1##*[!/]}"} # trim trailing slashes
|
||||
[ -d "${target:-/}" ] && target="$target/"
|
||||
|
||||
cd -P . 2>/dev/null || return 1
|
||||
while [ "$max_symlinks" -ge 0 ] && max_symlinks=$((max_symlinks - 1)); do
|
||||
if [ ! "$target" = "${target%/*}" ]; then
|
||||
case $target in
|
||||
/*) cd -P "${target%/*}/" 2>/dev/null || break ;;
|
||||
*) cd -P "./${target%/*}" 2>/dev/null || break ;;
|
||||
esac
|
||||
target=${target##*/}
|
||||
fi
|
||||
|
||||
if [ ! -L "$target" ]; then
|
||||
target="${PWD%/}${target:+/}${target}"
|
||||
printf '%s\n' "${target:-/}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# `ls -dl` format: "%s %u %s %s %u %s %s -> %s\n",
|
||||
# <file mode>, <number of links>, <owner name>, <group name>,
|
||||
# <size>, <date and time>, <pathname of link>, <contents of link>
|
||||
# https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
|
||||
link=$(ls -dl -- "$target" 2>/dev/null) || break
|
||||
target=${link#*" $target -> "}
|
||||
done
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
if ! BATS_PATH=$(bats_readlinkf "${BASH_SOURCE[0]}" 2>/dev/null); then
|
||||
fallback_to_readlinkf_posix
|
||||
BATS_PATH=$(bats_readlinkf "${BASH_SOURCE[0]}")
|
||||
fi
|
||||
|
||||
export BATS_ROOT=${BATS_PATH%/*/*}
|
||||
export -f bats_readlinkf
|
||||
exec env BATS_ROOT="$BATS_ROOT" "$BATS_ROOT/libexec/bats-core/bats" "$@"
|
98
extras/portable/test/bats/lib/bats-core/common.bash
Normal file
98
extras/portable/test/bats/lib/bats-core/common.bash
Normal file
@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
bats_prefix_lines_for_tap_output() {
|
||||
while IFS= read -r line; do
|
||||
printf '# %s\n' "$line" || break # avoid feedback loop when errors are redirected into BATS_OUT (see #353)
|
||||
done
|
||||
if [[ -n "$line" ]]; then
|
||||
printf '# %s\n' "$line"
|
||||
fi
|
||||
}
|
||||
|
||||
function bats_replace_filename() {
|
||||
local line
|
||||
while read -r line; do
|
||||
printf "%s\n" "${line//$BATS_TEST_SOURCE/$BATS_TEST_FILENAME}"
|
||||
done
|
||||
if [[ -n "$line" ]]; then
|
||||
printf "%s\n" "${line//$BATS_TEST_SOURCE/$BATS_TEST_FILENAME}"
|
||||
fi
|
||||
}
|
||||
|
||||
bats_quote_code() { # <var> <code>
|
||||
printf -v "$1" -- "%s%s%s" "$BATS_BEGIN_CODE_QUOTE" "$2" "$BATS_END_CODE_QUOTE"
|
||||
}
|
||||
|
||||
bats_check_valid_version() {
|
||||
if [[ ! $1 =~ [0-9]+.[0-9]+.[0-9]+ ]]; then
|
||||
printf "ERROR: version '%s' must be of format <major>.<minor>.<patch>!\n" "$1" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# compares two versions. Return 0 when version1 < version2
|
||||
bats_version_lt() { # <version1> <version2>
|
||||
bats_check_valid_version "$1"
|
||||
bats_check_valid_version "$2"
|
||||
|
||||
local -a version1_parts version2_parts
|
||||
IFS=. read -ra version1_parts <<< "$1"
|
||||
IFS=. read -ra version2_parts <<< "$2"
|
||||
|
||||
for i in {0..2}; do
|
||||
if (( version1_parts[i] < version2_parts[i] )); then
|
||||
return 0
|
||||
elif (( version1_parts[i] > version2_parts[i] )); then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
# if we made it this far, they are equal -> also not less then
|
||||
return 2 # use other failing return code to distinguish equal from gt
|
||||
}
|
||||
|
||||
# ensure a minimum version of bats is running or exit with failure
|
||||
bats_require_minimum_version() { # <required version>
|
||||
local required_minimum_version=$1
|
||||
|
||||
if bats_version_lt "$BATS_VERSION" "$required_minimum_version"; then
|
||||
printf "BATS_VERSION=%s does not meet required minimum %s\n" "$BATS_VERSION" "$required_minimum_version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if bats_version_lt "$BATS_GUARANTEED_MINIMUM_VERSION" "$required_minimum_version"; then
|
||||
BATS_GUARANTEED_MINIMUM_VERSION="$required_minimum_version"
|
||||
fi
|
||||
}
|
||||
|
||||
bats_binary_search() { # <search-value> <array-name>
|
||||
if [[ $# -ne 2 ]]; then
|
||||
printf "ERROR: bats_binary_search requires exactly 2 arguments: <search value> <array name>\n" >&2
|
||||
return 2
|
||||
fi
|
||||
|
||||
local -r search_value=$1 array_name=$2
|
||||
|
||||
# we'd like to test if array is set but we cannot distinguish unset from empty arrays, so we need to skip that
|
||||
|
||||
local start=0 mid end mid_value
|
||||
# start is inclusive, end is exclusive ...
|
||||
eval "end=\${#${array_name}[@]}"
|
||||
|
||||
# so start == end means empty search space
|
||||
while (( start < end )); do
|
||||
mid=$(( (start + end) / 2 ))
|
||||
eval "mid_value=\${${array_name}[$mid]}"
|
||||
if [[ "$mid_value" == "$search_value" ]]; then
|
||||
return 0
|
||||
elif [[ "$mid_value" < "$search_value" ]]; then
|
||||
# This branch excludes equality -> +1 to skip the mid element.
|
||||
# This +1 also avoids endless recursion on odd sized search ranges.
|
||||
start=$((mid + 1))
|
||||
else
|
||||
end=$mid
|
||||
fi
|
||||
done
|
||||
|
||||
# did not find it -> its not there
|
||||
return 1
|
||||
}
|
116
extras/portable/test/bats/lib/bats-core/formatter.bash
Normal file
116
extras/portable/test/bats/lib/bats-core/formatter.bash
Normal file
@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# reads (extended) bats tap streams from stdin and calls callback functions for each line
|
||||
# bats_tap_stream_plan <number of tests> -> when the test plan is encountered
|
||||
# bats_tap_stream_begin <test index> <test name> -> when a new test is begun WARNING: extended only
|
||||
# bats_tap_stream_ok [--duration <milliseconds] <test index> <test name> -> when a test was successful
|
||||
# bats_tap_stream_not_ok [--duration <milliseconds>] <test index> <test name> -> when a test has failed
|
||||
# bats_tap_stream_skipped <test index> <test name> <skip reason> -> when a test was skipped
|
||||
# bats_tap_stream_comment <comment text without leading '# '> <scope> -> when a comment line was encountered,
|
||||
# scope tells the last encountered of plan, begin, ok, not_ok, skipped, suite
|
||||
# bats_tap_stream_suite <file name> -> when a new file is begun WARNING: extended only
|
||||
# bats_tap_stream_unknown <full line> <scope> -> when a line is encountered that does not match the previous entries,
|
||||
# scope @see bats_tap_stream_comment
|
||||
# forwards all input as is, when there is no TAP test plan header
|
||||
function bats_parse_internal_extended_tap() {
|
||||
local header_pattern='[0-9]+\.\.[0-9]+'
|
||||
IFS= read -r header
|
||||
|
||||
if [[ "$header" =~ $header_pattern ]]; then
|
||||
bats_tap_stream_plan "${header:3}"
|
||||
else
|
||||
# If the first line isn't a TAP plan, print it and pass the rest through
|
||||
printf '%s\n' "$header"
|
||||
exec cat
|
||||
fi
|
||||
|
||||
ok_line_regexpr="ok ([0-9]+) (.*)"
|
||||
skip_line_regexpr="ok ([0-9]+) (.*) # skip( (.*))?$"
|
||||
not_ok_line_regexpr="not ok ([0-9]+) (.*)"
|
||||
|
||||
timing_expr="in ([0-9]+)ms$"
|
||||
local test_name begin_index ok_index not_ok_index index scope
|
||||
begin_index=0
|
||||
index=0
|
||||
scope=plan
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
'begin '*) # this might only be called in extended tap output
|
||||
((++begin_index))
|
||||
scope=begin
|
||||
test_name="${line#* "$begin_index" }"
|
||||
bats_tap_stream_begin "$begin_index" "$test_name"
|
||||
;;
|
||||
'ok '*)
|
||||
((++index))
|
||||
if [[ "$line" =~ $ok_line_regexpr ]]; then
|
||||
ok_index="${BASH_REMATCH[1]}"
|
||||
test_name="${BASH_REMATCH[2]}"
|
||||
if [[ "$line" =~ $skip_line_regexpr ]]; then
|
||||
scope=skipped
|
||||
test_name="${BASH_REMATCH[2]}" # cut off name before "# skip"
|
||||
local skip_reason="${BASH_REMATCH[4]}"
|
||||
bats_tap_stream_skipped "$ok_index" "$test_name" "$skip_reason"
|
||||
else
|
||||
scope=ok
|
||||
if [[ "$line" =~ $timing_expr ]]; then
|
||||
bats_tap_stream_ok --duration "${BASH_REMATCH[1]}" "$ok_index" "$test_name"
|
||||
else
|
||||
bats_tap_stream_ok "$ok_index" "$test_name"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
printf "ERROR: could not match ok line: %s" "$line" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
'not ok '*)
|
||||
((++index))
|
||||
scope=not_ok
|
||||
if [[ "$line" =~ $not_ok_line_regexpr ]]; then
|
||||
not_ok_index="${BASH_REMATCH[1]}"
|
||||
test_name="${BASH_REMATCH[2]}"
|
||||
if [[ "$line" =~ $timing_expr ]]; then
|
||||
bats_tap_stream_not_ok --duration "${BASH_REMATCH[1]}" "$not_ok_index" "$test_name"
|
||||
else
|
||||
bats_tap_stream_not_ok "$not_ok_index" "$test_name"
|
||||
fi
|
||||
else
|
||||
printf "ERROR: could not match not ok line: %s" "$line" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
'# '*)
|
||||
bats_tap_stream_comment "${line:2}" "$scope"
|
||||
;;
|
||||
'#')
|
||||
bats_tap_stream_comment "" "$scope"
|
||||
;;
|
||||
'suite '*)
|
||||
scope=suite
|
||||
# pass on the
|
||||
bats_tap_stream_suite "${line:6}"
|
||||
;;
|
||||
*)
|
||||
bats_tap_stream_unknown "$line" "$scope"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
normalize_base_path() { # <target variable> <base path>
|
||||
# the relative path root to use for reporting filenames
|
||||
# this is mainly intended for suite mode, where this will be the suite root folder
|
||||
local base_path="$2"
|
||||
# use the containing directory when --base-path is a file
|
||||
if [[ ! -d "$base_path" ]]; then
|
||||
base_path="$(dirname "$base_path")"
|
||||
fi
|
||||
# get the absolute path
|
||||
base_path="$(cd "$base_path" && pwd)"
|
||||
# ensure the path ends with / to strip that later on
|
||||
if [[ "${base_path}" != *"/" ]]; then
|
||||
base_path="$base_path/"
|
||||
fi
|
||||
printf -v "$1" "%s" "$base_path"
|
||||
}
|
22
extras/portable/test/bats/lib/bats-core/preprocessing.bash
Normal file
22
extras/portable/test/bats/lib/bats-core/preprocessing.bash
Normal file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BATS_TMPNAME="$BATS_RUN_TMPDIR/bats.$$"
|
||||
BATS_PARENT_TMPNAME="$BATS_RUN_TMPDIR/bats.$PPID"
|
||||
# shellcheck disable=SC2034
|
||||
BATS_OUT="${BATS_TMPNAME}.out" # used in bats-exec-file
|
||||
|
||||
bats_preprocess_source() {
|
||||
# export to make it visible to bats_evaluate_preprocessed_source
|
||||
# since the latter runs in bats-exec-test's bash while this runs in bats-exec-file's
|
||||
export BATS_TEST_SOURCE="${BATS_TMPNAME}.src"
|
||||
bats-preprocess "$BATS_TEST_FILENAME" >"$BATS_TEST_SOURCE"
|
||||
}
|
||||
|
||||
bats_evaluate_preprocessed_source() {
|
||||
if [[ -z "${BATS_TEST_SOURCE:-}" ]]; then
|
||||
BATS_TEST_SOURCE="${BATS_PARENT_TMPNAME}.src"
|
||||
fi
|
||||
# Dynamically loaded user files provided outside of Bats.
|
||||
# shellcheck disable=SC1090
|
||||
source "$BATS_TEST_SOURCE"
|
||||
}
|
107
extras/portable/test/bats/lib/bats-core/semaphore.bash
Normal file
107
extras/portable/test/bats/lib/bats-core/semaphore.bash
Normal file
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# setup the semaphore environment for the loading file
|
||||
bats_semaphore_setup() {
|
||||
export -f bats_semaphore_get_free_slot_count
|
||||
export -f bats_semaphore_acquire_while_locked
|
||||
export BATS_SEMAPHORE_DIR="$BATS_RUN_TMPDIR/semaphores"
|
||||
|
||||
if command -v flock >/dev/null; then
|
||||
bats_run_under_lock() {
|
||||
flock "$BATS_SEMAPHORE_DIR" "$@"
|
||||
}
|
||||
elif command -v shlock >/dev/null; then
|
||||
bats_run_under_lock() {
|
||||
local lockfile="$BATS_SEMAPHORE_DIR/shlock.lock"
|
||||
while ! shlock -p $$ -f "$lockfile"; do
|
||||
sleep 1
|
||||
done
|
||||
# we got the lock now, execute the command
|
||||
"$@"
|
||||
local status=$?
|
||||
# free the lock
|
||||
rm -f "$lockfile"
|
||||
return $status
|
||||
}
|
||||
else
|
||||
printf "ERROR: flock/shlock is required for parallelization within files!\n" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# $1 - output directory for stdout/stderr
|
||||
# $@ - command to run
|
||||
# run the given command in a semaphore
|
||||
# block when there is no free slot for the semaphore
|
||||
# when there is a free slot, run the command in background
|
||||
# gather the output of the command in files in the given directory
|
||||
bats_semaphore_run() {
|
||||
local output_dir=$1
|
||||
shift
|
||||
local semaphore_slot
|
||||
semaphore_slot=$(bats_semaphore_acquire_slot)
|
||||
bats_semaphore_release_wrapper "$output_dir" "$semaphore_slot" "$@" &
|
||||
printf "%d\n" "$!"
|
||||
}
|
||||
|
||||
# $1 - output directory for stdout/stderr
|
||||
# $@ - command to run
|
||||
# this wraps the actual function call to install some traps on exiting
|
||||
bats_semaphore_release_wrapper() {
|
||||
local output_dir="$1"
|
||||
local semaphore_name="$2"
|
||||
shift 2 # all other parameters will be use for the command to execute
|
||||
|
||||
# shellcheck disable=SC2064 # we want to expand the semaphore_name right now!
|
||||
trap "status=$?; bats_semaphore_release_slot '$semaphore_name'; exit $status" EXIT
|
||||
|
||||
mkdir -p "$output_dir"
|
||||
"$@" 2>"$output_dir/stderr" >"$output_dir/stdout"
|
||||
local status=$?
|
||||
|
||||
# bash bug: the exit trap is not called for the background process
|
||||
bats_semaphore_release_slot "$semaphore_name"
|
||||
trap - EXIT # avoid calling release twice
|
||||
return $status
|
||||
}
|
||||
|
||||
bats_semaphore_acquire_while_locked() {
|
||||
if [[ $(bats_semaphore_get_free_slot_count) -gt 0 ]]; then
|
||||
local slot=0
|
||||
while [[ -e "$BATS_SEMAPHORE_DIR/slot-$slot" ]]; do
|
||||
(( ++slot ))
|
||||
done
|
||||
if [[ $slot -lt $BATS_SEMAPHORE_NUMBER_OF_SLOTS ]]; then
|
||||
touch "$BATS_SEMAPHORE_DIR/slot-$slot" && printf "%d\n" "$slot" && return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# block until a semaphore slot becomes free
|
||||
# prints the number of the slot that it received
|
||||
bats_semaphore_acquire_slot() {
|
||||
mkdir -p "$BATS_SEMAPHORE_DIR"
|
||||
# wait for a slot to become free
|
||||
# TODO: avoid busy waiting by using signals -> this opens op prioritizing possibilities as well
|
||||
while true; do
|
||||
# don't lock for reading, we are fine with spuriously getting no free slot
|
||||
if [[ $(bats_semaphore_get_free_slot_count) -gt 0 ]]; then
|
||||
bats_run_under_lock bash -c bats_semaphore_acquire_while_locked && break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
bats_semaphore_release_slot() {
|
||||
# we don't need to lock this, since only our process owns this file
|
||||
# and freeing a semaphore cannot lead to conflicts with others
|
||||
rm "$BATS_SEMAPHORE_DIR/slot-$1" # this will fail if we had not acquired a semaphore!
|
||||
}
|
||||
|
||||
bats_semaphore_get_free_slot_count() {
|
||||
# find might error out without returning something useful when a file is deleted,
|
||||
# while the directory is traversed -> only continue when there was no error
|
||||
until used_slots=$(find "$BATS_SEMAPHORE_DIR" -name 'slot-*' 2>/dev/null | wc -l); do :; done
|
||||
echo $(( BATS_SEMAPHORE_NUMBER_OF_SLOTS - used_slots ))
|
||||
}
|
357
extras/portable/test/bats/lib/bats-core/test_functions.bash
Normal file
357
extras/portable/test/bats/lib/bats-core/test_functions.bash
Normal file
@ -0,0 +1,357 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BATS_TEST_DIRNAME="${BATS_TEST_FILENAME%/*}"
|
||||
BATS_TEST_NAMES=()
|
||||
|
||||
# shellcheck source=lib/bats-core/warnings.bash
|
||||
source "$BATS_ROOT/lib/bats-core/warnings.bash"
|
||||
|
||||
# find_in_bats_lib_path echoes the first recognized load path to
|
||||
# a library in BATS_LIB_PATH or relative to BATS_TEST_DIRNAME.
|
||||
#
|
||||
# Libraries relative to BATS_TEST_DIRNAME take precedence over
|
||||
# BATS_LIB_PATH.
|
||||
#
|
||||
# Library load paths are recognized using find_library_load_path.
|
||||
#
|
||||
# If no library is found find_in_bats_lib_path returns 1.
|
||||
find_in_bats_lib_path() { # <return-var> <library-name>
|
||||
local return_var="${1:?}"
|
||||
local library_name="${2:?}"
|
||||
|
||||
local -a bats_lib_paths
|
||||
IFS=: read -ra bats_lib_paths <<< "$BATS_LIB_PATH"
|
||||
|
||||
for path in "${bats_lib_paths[@]}"; do
|
||||
if [[ -f "$path/$library_name" ]]; then
|
||||
printf -v "$return_var" "%s" "$path/$library_name"
|
||||
# A library load path was found, return
|
||||
return 0
|
||||
elif [[ -f "$path/$library_name/load.bash" ]]; then
|
||||
printf -v "$return_var" "%s" "$path/$library_name/load.bash"
|
||||
# A library load path was found, return
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# bats_internal_load expects an absolute path that is a library load path.
|
||||
#
|
||||
# If the library load path points to a file (a library loader) it is
|
||||
# sourced.
|
||||
#
|
||||
# If it points to a directory all files ending in .bash inside of the
|
||||
# directory are sourced.
|
||||
#
|
||||
# If the sourcing of the library loader or of a file in a library
|
||||
# directory fails bats_internal_load prints an error message and returns 1.
|
||||
#
|
||||
# If the passed library load path is not absolute or is not a valid file
|
||||
# or directory bats_internal_load prints an error message and returns 1.
|
||||
bats_internal_load() {
|
||||
local library_load_path="${1:?}"
|
||||
|
||||
if [[ "${library_load_path:0:1}" != / ]]; then
|
||||
printf "Passed library load path is not an absolute path: %s\n" "$library_load_path" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# library_load_path is a library loader
|
||||
if [[ -f "$library_load_path" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
if ! source "$library_load_path"; then
|
||||
printf "Error while sourcing library loader at '%s'\n" "$library_load_path" >&2
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf "Passed library load path is neither a library loader nor library directory: %s\n" "$library_load_path" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# bats_load_safe accepts an argument called 'slug' and attempts to find and
|
||||
# source a library based on the slug.
|
||||
#
|
||||
# A slug can be an absolute path, a library name or a relative path.
|
||||
#
|
||||
# If the slug is an absolute path bats_load_safe attempts to find the library
|
||||
# load path using find_library_load_path.
|
||||
# What is considered a library load path is documented in the
|
||||
# documentation for find_library_load_path.
|
||||
#
|
||||
# If the slug is not an absolute path it is considered a library name or
|
||||
# relative path. bats_load_safe attempts to find the library load path using
|
||||
# find_in_bats_lib_path.
|
||||
#
|
||||
# If bats_load_safe can find a library load path it is passed to bats_internal_load.
|
||||
# If bats_internal_load fails bats_load_safe returns 1.
|
||||
#
|
||||
# If no library load path can be found bats_load_safe prints an error message
|
||||
# and returns 1.
|
||||
bats_load_safe() {
|
||||
local slug="${1:?}"
|
||||
if [[ ${slug:0:1} != / ]]; then # relative paths are relative to BATS_TEST_DIRNAME
|
||||
slug="$BATS_TEST_DIRNAME/$slug"
|
||||
fi
|
||||
|
||||
if [[ -f "$slug.bash" ]]; then
|
||||
bats_internal_load "$slug.bash"
|
||||
return $?
|
||||
elif [[ -f "$slug" ]]; then
|
||||
bats_internal_load "$slug"
|
||||
return $?
|
||||
fi
|
||||
|
||||
# loading from PATH (retained for backwards compatibility)
|
||||
if [[ ! -f "$1" ]] && type -P "$1" >/dev/null; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$1"
|
||||
return $?
|
||||
fi
|
||||
|
||||
# No library load path can be found
|
||||
printf "bats_load_safe: Could not find '%s'[.bash]\n" "$slug" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
bats_require_lib_path() {
|
||||
if [[ -z "${BATS_LIB_PATH:-}" ]]; then
|
||||
printf "%s: requires BATS_LIB_PATH to be set!\n" "${FUNCNAME[1]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
bats_load_library_safe() { # <slug>
|
||||
local slug="${1:?}" library_path
|
||||
|
||||
bats_require_lib_path
|
||||
|
||||
# Check for library load paths in BATS_TEST_DIRNAME and BATS_LIB_PATH
|
||||
if [[ ${slug:0:1} != / ]]; then
|
||||
find_in_bats_lib_path library_path "$slug"
|
||||
if [[ -z "$library_path" ]]; then
|
||||
printf "Could not find library '%s' relative to test file or in BATS_LIB_PATH\n" "$slug" >&2
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# absolute paths are taken as is
|
||||
library_path="$slug"
|
||||
if [[ ! -f "$library_path" ]]; then
|
||||
printf "Could not find library on absolute path '%s'\n" "$library_path" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
bats_internal_load "$library_path"
|
||||
return $?
|
||||
}
|
||||
|
||||
# immediately exit on error, use bats_load_library_safe to catch and handle errors
|
||||
bats_load_library() { # <slug>
|
||||
bats_require_lib_path
|
||||
if ! bats_load_library_safe "$@"; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# load acts like bats_load_safe but exits the shell instead of returning 1.
|
||||
load() {
|
||||
if ! bats_load_safe "$@"; then
|
||||
echo "${FUNCNAME[0]} $LINENO" >&3
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
bats_redirect_stderr_into_file() {
|
||||
"$@" 2>>"$bats_run_separate_stderr_file" # use >> to see collisions' content
|
||||
}
|
||||
|
||||
bats_merge_stdout_and_stderr() {
|
||||
"$@" 2>&1
|
||||
}
|
||||
|
||||
# write separate lines from <input-var> into <output-array>
|
||||
bats_separate_lines() { # <output-array> <input-var>
|
||||
local output_array_name="$1"
|
||||
local input_var_name="$2"
|
||||
if [[ $keep_empty_lines ]]; then
|
||||
local bats_separate_lines_lines=()
|
||||
if [[ -n "${!input_var_name}" ]]; then # avoid getting an empty line for empty input
|
||||
while IFS= read -r line; do
|
||||
bats_separate_lines_lines+=("$line")
|
||||
done <<<"${!input_var_name}"
|
||||
fi
|
||||
eval "${output_array_name}=(\"\${bats_separate_lines_lines[@]}\")"
|
||||
else
|
||||
# shellcheck disable=SC2034,SC2206
|
||||
IFS=$'\n' read -d '' -r -a "$output_array_name" <<<"${!input_var_name}" || true # don't fail due to EOF
|
||||
fi
|
||||
}
|
||||
|
||||
run() { # [!|-N] [--keep-empty-lines] [--separate-stderr] [--] <command to run...>
|
||||
# This has to be restored on exit from this function to avoid leaking our trap INT into surrounding code.
|
||||
# Non zero exits won't restore under the assumption that they will fail the test before it can be aborted,
|
||||
# which allows us to avoid duplicating the restore code on every exit path
|
||||
trap bats_interrupt_trap_in_run INT
|
||||
local expected_rc=
|
||||
local keep_empty_lines=
|
||||
local output_case=merged
|
||||
local has_flags=
|
||||
# parse options starting with -
|
||||
while [[ $# -gt 0 ]] && [[ $1 == -* || $1 == '!' ]]; do
|
||||
has_flags=1
|
||||
case "$1" in
|
||||
'!')
|
||||
expected_rc=-1
|
||||
;;
|
||||
-[0-9]*)
|
||||
expected_rc=${1#-}
|
||||
if [[ $expected_rc =~ [^0-9] ]]; then
|
||||
printf "Usage error: run: '-NNN' requires numeric NNN (got: %s)\n" "$expected_rc" >&2
|
||||
return 1
|
||||
elif [[ $expected_rc -gt 255 ]]; then
|
||||
printf "Usage error: run: '-NNN': NNN must be <= 255 (got: %d)\n" "$expected_rc" >&2
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
--keep-empty-lines)
|
||||
keep_empty_lines=1
|
||||
;;
|
||||
--separate-stderr)
|
||||
output_case="separate"
|
||||
;;
|
||||
--)
|
||||
shift # eat the -- before breaking away
|
||||
break
|
||||
;;
|
||||
*)
|
||||
printf "Usage error: unknown flag '%s'" "$1" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ -n $has_flags ]]; then
|
||||
bats_warn_minimum_guaranteed_version "Using flags on \`run\`" 1.5.0
|
||||
fi
|
||||
|
||||
local pre_command=
|
||||
|
||||
case "$output_case" in
|
||||
merged) # redirects stderr into stdout and fills only $output/$lines
|
||||
pre_command=bats_merge_stdout_and_stderr
|
||||
;;
|
||||
separate) # splits stderr into own file and fills $stderr/$stderr_lines too
|
||||
local bats_run_separate_stderr_file
|
||||
bats_run_separate_stderr_file="$(mktemp "${BATS_TEST_TMPDIR}/separate-stderr-XXXXXX")"
|
||||
pre_command=bats_redirect_stderr_into_file
|
||||
;;
|
||||
esac
|
||||
|
||||
local origFlags="$-"
|
||||
set +eET
|
||||
local origIFS="$IFS"
|
||||
if [[ $keep_empty_lines ]]; then
|
||||
# 'output', 'status', 'lines' are global variables available to tests.
|
||||
# preserve trailing newlines by appending . and removing it later
|
||||
# shellcheck disable=SC2034
|
||||
output="$($pre_command "$@"; status=$?; printf .; exit $status)" && status=0 || status=$?
|
||||
output="${output%.}"
|
||||
else
|
||||
# 'output', 'status', 'lines' are global variables available to tests.
|
||||
# shellcheck disable=SC2034
|
||||
output="$($pre_command "$@")" && status=0 || status=$?
|
||||
fi
|
||||
|
||||
bats_separate_lines lines output
|
||||
|
||||
if [[ "$output_case" == separate ]]; then
|
||||
# shellcheck disable=SC2034
|
||||
read -d '' -r stderr < "$bats_run_separate_stderr_file"
|
||||
bats_separate_lines stderr_lines stderr
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
BATS_RUN_COMMAND="${*}"
|
||||
IFS="$origIFS"
|
||||
set "-$origFlags"
|
||||
|
||||
if [[ ${BATS_VERBOSE_RUN:-} ]]; then
|
||||
printf "%s\n" "$output"
|
||||
fi
|
||||
|
||||
|
||||
if [[ -n "$expected_rc" ]]; then
|
||||
if [[ "$expected_rc" = "-1" ]]; then
|
||||
if [[ "$status" -eq 0 ]]; then
|
||||
BATS_ERROR_SUFFIX=", expected nonzero exit code!"
|
||||
return 1
|
||||
fi
|
||||
elif [ "$status" -ne "$expected_rc" ]; then
|
||||
# shellcheck disable=SC2034
|
||||
BATS_ERROR_SUFFIX=", expected exit code $expected_rc, got $status"
|
||||
return 1
|
||||
fi
|
||||
elif [[ "$status" -eq 127 ]]; then # "command not found"
|
||||
bats_generate_warning 1 "$BATS_RUN_COMMAND"
|
||||
fi
|
||||
# don't leak our trap into surrounding code
|
||||
trap bats_interrupt_trap INT
|
||||
}
|
||||
|
||||
setup() {
|
||||
return 0
|
||||
}
|
||||
|
||||
teardown() {
|
||||
return 0
|
||||
}
|
||||
|
||||
skip() {
|
||||
# if this is a skip in teardown ...
|
||||
if [[ -n "${BATS_TEARDOWN_STARTED-}" ]]; then
|
||||
# ... we want to skip the rest of teardown.
|
||||
# communicate to bats_exit_trap that the teardown was completed without error
|
||||
# shellcheck disable=SC2034
|
||||
BATS_TEARDOWN_COMPLETED=1
|
||||
# if we are already in the exit trap (e.g. due to previous skip) ...
|
||||
if [[ "$BATS_TEARDOWN_STARTED" == as-exit-trap ]]; then
|
||||
# ... we need to do the rest of the tear_down_trap that would otherwise be skipped after the next call to exit
|
||||
bats_exit_trap
|
||||
# and then do the exit (at the end of this function)
|
||||
fi
|
||||
# if we aren't in exit trap, the normal exit handling should suffice
|
||||
else
|
||||
# ... this is either skip in test or skip in setup.
|
||||
# Following variables are used in bats-exec-test which sources this file
|
||||
# shellcheck disable=SC2034
|
||||
BATS_TEST_SKIPPED="${1:-1}"
|
||||
# shellcheck disable=SC2034
|
||||
BATS_TEST_COMPLETED=1
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
bats_test_begin() {
|
||||
BATS_TEST_DESCRIPTION="$1"
|
||||
if [[ -n "$BATS_EXTENDED_SYNTAX" ]]; then
|
||||
printf 'begin %d %s\n' "$BATS_SUITE_TEST_NUMBER" "${BATS_TEST_NAME_PREFIX:-}$BATS_TEST_DESCRIPTION" >&3
|
||||
fi
|
||||
setup
|
||||
}
|
||||
|
||||
bats_test_function() {
|
||||
local test_name="$1"
|
||||
BATS_TEST_NAMES+=("$test_name")
|
||||
}
|
||||
|
||||
# decides whether a failed test should be run again
|
||||
bats_should_retry_test() {
|
||||
# test try number starts at 1
|
||||
# 0 retries means run only first try
|
||||
(( BATS_TEST_TRY_NUMBER <= BATS_TEST_RETRIES ))
|
||||
}
|
386
extras/portable/test/bats/lib/bats-core/tracing.bash
Normal file
386
extras/portable/test/bats/lib/bats-core/tracing.bash
Normal file
@ -0,0 +1,386 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# shellcheck source=lib/bats-core/common.bash
|
||||
source "$BATS_ROOT/lib/bats-core/common.bash"
|
||||
|
||||
bats_capture_stack_trace() {
|
||||
local test_file
|
||||
local funcname
|
||||
local i
|
||||
|
||||
BATS_DEBUG_LAST_STACK_TRACE=()
|
||||
|
||||
for ((i = 2; i != ${#FUNCNAME[@]}; ++i)); do
|
||||
# Use BATS_TEST_SOURCE if necessary to work around Bash < 4.4 bug whereby
|
||||
# calling an exported function erases the test file's BASH_SOURCE entry.
|
||||
test_file="${BASH_SOURCE[$i]:-$BATS_TEST_SOURCE}"
|
||||
funcname="${FUNCNAME[$i]}"
|
||||
BATS_DEBUG_LAST_STACK_TRACE+=("${BASH_LINENO[$((i-1))]} $funcname $test_file")
|
||||
case "$funcname" in
|
||||
"$BATS_TEST_NAME" | setup | teardown | setup_file | teardown_file | setup_suite | teardown_suite)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
if [[ "${BASH_SOURCE[$i + 1]:-}" == *"bats-exec-file" ]] && [[ "$funcname" == 'source' ]]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
bats_get_failure_stack_trace() {
|
||||
local stack_trace_var
|
||||
# See bats_debug_trap for details.
|
||||
if [[ -n "${BATS_DEBUG_LAST_STACK_TRACE_IS_VALID:-}" ]]; then
|
||||
stack_trace_var=BATS_DEBUG_LAST_STACK_TRACE
|
||||
else
|
||||
stack_trace_var=BATS_DEBUG_LASTLAST_STACK_TRACE
|
||||
fi
|
||||
# shellcheck disable=SC2016
|
||||
eval "$(printf \
|
||||
'%s=(${%s[@]+"${%s[@]}"})' \
|
||||
"${1}" \
|
||||
"${stack_trace_var}" \
|
||||
"${stack_trace_var}")"
|
||||
}
|
||||
|
||||
bats_print_stack_trace() {
|
||||
local frame
|
||||
local index=1
|
||||
local count="${#@}"
|
||||
local filename
|
||||
local lineno
|
||||
|
||||
for frame in "$@"; do
|
||||
bats_frame_filename "$frame" 'filename'
|
||||
bats_trim_filename "$filename" 'filename'
|
||||
bats_frame_lineno "$frame" 'lineno'
|
||||
|
||||
printf '%s' "${BATS_STACK_TRACE_PREFIX-# }"
|
||||
if [[ $index -eq 1 ]]; then
|
||||
printf '('
|
||||
else
|
||||
printf ' '
|
||||
fi
|
||||
|
||||
local fn
|
||||
bats_frame_function "$frame" 'fn'
|
||||
if [[ "$fn" != "$BATS_TEST_NAME" ]] &&
|
||||
# don't print "from function `source'"",
|
||||
# when failing in free code during `source $test_file` from bats-exec-file
|
||||
! [[ "$fn" == 'source' && $index -eq $count ]]; then
|
||||
local quoted_fn
|
||||
bats_quote_code quoted_fn "$fn"
|
||||
printf "from function %s " "$quoted_fn"
|
||||
fi
|
||||
|
||||
if [[ $index -eq $count ]]; then
|
||||
printf 'in test file %s, line %d)\n' "$filename" "$lineno"
|
||||
else
|
||||
printf 'in file %s, line %d,\n' "$filename" "$lineno"
|
||||
fi
|
||||
|
||||
((++index))
|
||||
done
|
||||
}
|
||||
|
||||
bats_print_failed_command() {
|
||||
local stack_trace=("${@}")
|
||||
if [[ ${#stack_trace[@]} -eq 0 ]]; then
|
||||
return
|
||||
fi
|
||||
local frame="${stack_trace[${#stack_trace[@]} - 1]}"
|
||||
local filename
|
||||
local lineno
|
||||
local failed_line
|
||||
local failed_command
|
||||
|
||||
bats_frame_filename "$frame" 'filename'
|
||||
bats_frame_lineno "$frame" 'lineno'
|
||||
bats_extract_line "$filename" "$lineno" 'failed_line'
|
||||
bats_strip_string "$failed_line" 'failed_command'
|
||||
local quoted_failed_command
|
||||
bats_quote_code quoted_failed_command "$failed_command"
|
||||
printf '# %s ' "${quoted_failed_command}"
|
||||
|
||||
if [[ "$BATS_ERROR_STATUS" -eq 1 ]]; then
|
||||
printf 'failed%s\n' "$BATS_ERROR_SUFFIX"
|
||||
else
|
||||
printf 'failed with status %d%s\n' "$BATS_ERROR_STATUS" "$BATS_ERROR_SUFFIX"
|
||||
fi
|
||||
}
|
||||
|
||||
bats_frame_lineno() {
|
||||
printf -v "$2" '%s' "${1%% *}"
|
||||
}
|
||||
|
||||
bats_frame_function() {
|
||||
local __bff_function="${1#* }"
|
||||
printf -v "$2" '%s' "${__bff_function%% *}"
|
||||
}
|
||||
|
||||
bats_frame_filename() {
|
||||
local __bff_filename="${1#* }"
|
||||
__bff_filename="${__bff_filename#* }"
|
||||
|
||||
if [[ "$__bff_filename" == "$BATS_TEST_SOURCE" ]]; then
|
||||
__bff_filename="$BATS_TEST_FILENAME"
|
||||
fi
|
||||
printf -v "$2" '%s' "$__bff_filename"
|
||||
}
|
||||
|
||||
bats_extract_line() {
|
||||
local __bats_extract_line_line
|
||||
local __bats_extract_line_index=0
|
||||
|
||||
while IFS= read -r __bats_extract_line_line; do
|
||||
if [[ "$((++__bats_extract_line_index))" -eq "$2" ]]; then
|
||||
printf -v "$3" '%s' "${__bats_extract_line_line%$'\r'}"
|
||||
break
|
||||
fi
|
||||
done <"$1"
|
||||
}
|
||||
|
||||
bats_strip_string() {
|
||||
[[ "$1" =~ ^[[:space:]]*(.*)[[:space:]]*$ ]]
|
||||
printf -v "$2" '%s' "${BASH_REMATCH[1]}"
|
||||
}
|
||||
|
||||
bats_trim_filename() {
|
||||
printf -v "$2" '%s' "${1#"$BATS_CWD"/}"
|
||||
}
|
||||
|
||||
# normalize a windows path from e.g. C:/directory to /c/directory
|
||||
# The path must point to an existing/accessable directory, not a file!
|
||||
bats_normalize_windows_dir_path() { # <output-var> <path>
|
||||
local output_var="$1" path="$2"
|
||||
if [[ "$output_var" != NORMALIZED_INPUT ]]; then
|
||||
local NORMALIZED_INPUT
|
||||
fi
|
||||
if [[ $path == ?:* ]]; then
|
||||
NORMALIZED_INPUT="$(cd "$path" || exit 1; pwd)"
|
||||
else
|
||||
NORMALIZED_INPUT="$path"
|
||||
fi
|
||||
printf -v "$output_var" "%s" "$NORMALIZED_INPUT"
|
||||
}
|
||||
|
||||
bats_emit_trace() {
|
||||
if [[ $BATS_TRACE_LEVEL -gt 0 ]]; then
|
||||
local line=${BASH_LINENO[1]}
|
||||
# shellcheck disable=SC2016
|
||||
if [[ $BASH_COMMAND != '"$BATS_TEST_NAME" >> "$BATS_OUT" 2>&1 4>&1' && $BASH_COMMAND != "bats_test_begin "* ]] && # don't emit these internal calls
|
||||
[[ $BASH_COMMAND != "$BATS_LAST_BASH_COMMAND" || $line != "$BATS_LAST_BASH_LINENO" ]] &&
|
||||
# avoid printing a function twice (at call site and at definition site)
|
||||
[[ $BASH_COMMAND != "$BATS_LAST_BASH_COMMAND" || ${BASH_LINENO[2]} != "$BATS_LAST_BASH_LINENO" || ${BASH_SOURCE[3]} != "$BATS_LAST_BASH_SOURCE" ]]; then
|
||||
local file="${BASH_SOURCE[2]}" # index 2: skip over bats_emit_trace and bats_debug_trap
|
||||
if [[ $file == "${BATS_TEST_SOURCE}" ]]; then
|
||||
file="$BATS_TEST_FILENAME"
|
||||
fi
|
||||
local padding='$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$'
|
||||
if (( BATS_LAST_STACK_DEPTH != ${#BASH_LINENO[@]} )); then
|
||||
printf '%s [%s:%d]\n' "${padding::${#BASH_LINENO[@]}-4}" "${file##*/}" "$line" >&4
|
||||
fi
|
||||
printf '%s %s\n' "${padding::${#BASH_LINENO[@]}-4}" "$BASH_COMMAND" >&4
|
||||
BATS_LAST_BASH_COMMAND="$BASH_COMMAND"
|
||||
BATS_LAST_BASH_LINENO="$line"
|
||||
BATS_LAST_BASH_SOURCE="${BASH_SOURCE[2]}"
|
||||
BATS_LAST_STACK_DEPTH="${#BASH_LINENO[@]}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# bats_debug_trap tracks the last line of code executed within a test. This is
|
||||
# necessary because $BASH_LINENO is often incorrect inside of ERR and EXIT
|
||||
# trap handlers.
|
||||
#
|
||||
# Below are tables describing different command failure scenarios and the
|
||||
# reliability of $BASH_LINENO within different the executed DEBUG, ERR, and EXIT
|
||||
# trap handlers. Naturally, the behaviors change between versions of Bash.
|
||||
#
|
||||
# Table rows should be read left to right. For example, on bash version
|
||||
# 4.0.44(2)-release, if a test executes `false` (or any other failing external
|
||||
# command), bash will do the following in order:
|
||||
# 1. Call the DEBUG trap handler (bats_debug_trap) with $BASH_LINENO referring
|
||||
# to the source line containing the `false` command, then
|
||||
# 2. Call the DEBUG trap handler again, but with an incorrect $BASH_LINENO, then
|
||||
# 3. Call the ERR trap handler, but with a (possibly-different) incorrect
|
||||
# $BASH_LINENO, then
|
||||
# 4. Call the DEBUG trap handler again, but with $BASH_LINENO set to 1, then
|
||||
# 5. Call the EXIT trap handler, with $BASH_LINENO set to 1.
|
||||
#
|
||||
# bash version 4.4.20(1)-release
|
||||
# command | first DEBUG | second DEBUG | ERR | third DEBUG | EXIT
|
||||
# -------------+-------------+--------------+---------+-------------+--------
|
||||
# false | OK | OK | OK | BAD[1] | BAD[1]
|
||||
# [[ 1 = 2 ]] | OK | BAD[2] | BAD[2] | BAD[1] | BAD[1]
|
||||
# (( 1 = 2 )) | OK | BAD[2] | BAD[2] | BAD[1] | BAD[1]
|
||||
# ! true | OK | --- | BAD[4] | --- | BAD[1]
|
||||
# $var_dne | OK | --- | --- | BAD[1] | BAD[1]
|
||||
# source /dne | OK | --- | --- | BAD[1] | BAD[1]
|
||||
#
|
||||
# bash version 4.0.44(2)-release
|
||||
# command | first DEBUG | second DEBUG | ERR | third DEBUG | EXIT
|
||||
# -------------+-------------+--------------+---------+-------------+--------
|
||||
# false | OK | BAD[3] | BAD[3] | BAD[1] | BAD[1]
|
||||
# [[ 1 = 2 ]] | OK | --- | BAD[3] | --- | BAD[1]
|
||||
# (( 1 = 2 )) | OK | --- | BAD[3] | --- | BAD[1]
|
||||
# ! true | OK | --- | BAD[3] | --- | BAD[1]
|
||||
# $var_dne | OK | --- | --- | BAD[1] | BAD[1]
|
||||
# source /dne | OK | --- | --- | BAD[1] | BAD[1]
|
||||
#
|
||||
# [1] The reported line number is always 1.
|
||||
# [2] The reported source location is that of the beginning of the function
|
||||
# calling the command.
|
||||
# [3] The reported line is that of the last command executed in the DEBUG trap
|
||||
# handler.
|
||||
# [4] The reported source location is that of the call to the function calling
|
||||
# the command.
|
||||
bats_debug_trap() {
|
||||
# on windows we sometimes get a mix of paths (when install via nmp install -g)
|
||||
# which have C:/... or /c/... comparing them is going to be problematic.
|
||||
# We need to normalize them to a common format!
|
||||
local NORMALIZED_INPUT
|
||||
bats_normalize_windows_dir_path NORMALIZED_INPUT "${1%/*}"
|
||||
local file_excluded='' path
|
||||
for path in "${BATS_DEBUG_EXCLUDE_PATHS[@]}"; do
|
||||
if [[ "$NORMALIZED_INPUT" == "$path"* ]]; then
|
||||
file_excluded=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# don't update the trace within library functions or we get backtraces from inside traps
|
||||
# also don't record new stack traces while handling interruptions, to avoid overriding the interrupted command
|
||||
if [[ -z "$file_excluded" && "${BATS_INTERRUPTED-NOTSET}" == NOTSET ]]; then
|
||||
BATS_DEBUG_LASTLAST_STACK_TRACE=(
|
||||
${BATS_DEBUG_LAST_STACK_TRACE[@]+"${BATS_DEBUG_LAST_STACK_TRACE[@]}"}
|
||||
)
|
||||
|
||||
BATS_DEBUG_LAST_LINENO=(${BASH_LINENO[@]+"${BASH_LINENO[@]}"})
|
||||
BATS_DEBUG_LAST_SOURCE=(${BASH_SOURCE[@]+"${BASH_SOURCE[@]}"})
|
||||
bats_capture_stack_trace
|
||||
bats_emit_trace
|
||||
fi
|
||||
}
|
||||
|
||||
# For some versions of Bash, the `ERR` trap may not always fire for every
|
||||
# command failure, but the `EXIT` trap will. Also, some command failures may not
|
||||
# set `$?` properly. See #72 and #81 for details.
|
||||
#
|
||||
# For this reason, we call `bats_check_status_from_trap` at the very beginning
|
||||
# of `bats_teardown_trap` and check the value of `$BATS_TEST_COMPLETED` before
|
||||
# taking other actions. We also adjust the exit status value if needed.
|
||||
#
|
||||
# See `bats_exit_trap` for an additional EXIT error handling case when `$?`
|
||||
# isn't set properly during `teardown()` errors.
|
||||
bats_check_status_from_trap() {
|
||||
local status="$?"
|
||||
if [[ -z "${BATS_TEST_COMPLETED:-}" ]]; then
|
||||
BATS_ERROR_STATUS="${BATS_ERROR_STATUS:-$status}"
|
||||
if [[ "$BATS_ERROR_STATUS" -eq 0 ]]; then
|
||||
BATS_ERROR_STATUS=1
|
||||
fi
|
||||
trap - DEBUG
|
||||
fi
|
||||
}
|
||||
|
||||
bats_add_debug_exclude_path() { # <path>
|
||||
if [[ -z "$1" ]]; then # don't exclude everything
|
||||
printf "bats_add_debug_exclude_path: Exclude path must not be empty!\n" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ "$OSTYPE" == cygwin || "$OSTYPE" == msys ]]; then
|
||||
local normalized_dir
|
||||
bats_normalize_windows_dir_path normalized_dir "$1"
|
||||
BATS_DEBUG_EXCLUDE_PATHS+=("$normalized_dir")
|
||||
else
|
||||
BATS_DEBUG_EXCLUDE_PATHS+=("$1")
|
||||
fi
|
||||
}
|
||||
|
||||
bats_setup_tracing() {
|
||||
# Variables for capturing accurate stack traces. See bats_debug_trap for
|
||||
# details.
|
||||
#
|
||||
# BATS_DEBUG_LAST_LINENO, BATS_DEBUG_LAST_SOURCE, and
|
||||
# BATS_DEBUG_LAST_STACK_TRACE hold data from the most recent call to
|
||||
# bats_debug_trap.
|
||||
#
|
||||
# BATS_DEBUG_LASTLAST_STACK_TRACE holds data from two bats_debug_trap calls
|
||||
# ago.
|
||||
#
|
||||
# BATS_DEBUG_LAST_STACK_TRACE_IS_VALID indicates that
|
||||
# BATS_DEBUG_LAST_STACK_TRACE contains the stack trace of the test's error. If
|
||||
# unset, BATS_DEBUG_LAST_STACK_TRACE is unreliable and
|
||||
# BATS_DEBUG_LASTLAST_STACK_TRACE should be used instead.
|
||||
BATS_DEBUG_LASTLAST_STACK_TRACE=()
|
||||
BATS_DEBUG_LAST_LINENO=()
|
||||
BATS_DEBUG_LAST_SOURCE=()
|
||||
BATS_DEBUG_LAST_STACK_TRACE=()
|
||||
BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=
|
||||
BATS_ERROR_SUFFIX=
|
||||
BATS_DEBUG_EXCLUDE_PATHS=()
|
||||
# exclude some paths by default
|
||||
bats_add_debug_exclude_path "$BATS_ROOT/lib/"
|
||||
bats_add_debug_exclude_path "$BATS_ROOT/libexec/"
|
||||
|
||||
|
||||
exec 4<&1 # used for tracing
|
||||
if [[ "${BATS_TRACE_LEVEL:-0}" -gt 0 ]]; then
|
||||
# avoid undefined variable errors
|
||||
BATS_LAST_BASH_COMMAND=
|
||||
BATS_LAST_BASH_LINENO=
|
||||
BATS_LAST_BASH_SOURCE=
|
||||
BATS_LAST_STACK_DEPTH=
|
||||
# try to exclude helper libraries if found, this is only relevant for tracing
|
||||
while read -r path; do
|
||||
bats_add_debug_exclude_path "$path"
|
||||
done < <(find "$PWD" -type d -name bats-assert -o -name bats-support)
|
||||
fi
|
||||
|
||||
local exclude_paths path
|
||||
# exclude user defined libraries
|
||||
IFS=':' read -r exclude_paths <<< "${BATS_DEBUG_EXCLUDE_PATHS:-}"
|
||||
for path in "${exclude_paths[@]}"; do
|
||||
if [[ -n "$path" ]]; then
|
||||
bats_add_debug_exclude_path "$path"
|
||||
fi
|
||||
done
|
||||
|
||||
# turn on traps after setting excludes to avoid tracing the exclude setup
|
||||
trap 'bats_debug_trap "$BASH_SOURCE"' DEBUG
|
||||
trap 'bats_error_trap' ERR
|
||||
}
|
||||
|
||||
bats_error_trap() {
|
||||
bats_check_status_from_trap
|
||||
|
||||
# If necessary, undo the most recent stack trace captured by bats_debug_trap.
|
||||
# See bats_debug_trap for details.
|
||||
if [[ "${BASH_LINENO[*]}" = "${BATS_DEBUG_LAST_LINENO[*]:-}"
|
||||
&& "${BASH_SOURCE[*]}" = "${BATS_DEBUG_LAST_SOURCE[*]:-}"
|
||||
&& -z "$BATS_DEBUG_LAST_STACK_TRACE_IS_VALID" ]]; then
|
||||
BATS_DEBUG_LAST_STACK_TRACE=(
|
||||
${BATS_DEBUG_LASTLAST_STACK_TRACE[@]+"${BATS_DEBUG_LASTLAST_STACK_TRACE[@]}"}
|
||||
)
|
||||
fi
|
||||
BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=1
|
||||
}
|
||||
|
||||
bats_interrupt_trap() {
|
||||
# mark the interruption, to handle during exit
|
||||
BATS_INTERRUPTED=true
|
||||
BATS_ERROR_STATUS=130
|
||||
# debug trap fires before interrupt trap but gets wrong linenumber (line 1)
|
||||
# -> use last stack trace
|
||||
exit $BATS_ERROR_STATUS
|
||||
}
|
||||
|
||||
# this is used inside run()
|
||||
bats_interrupt_trap_in_run() {
|
||||
# mark the interruption, to handle during exit
|
||||
BATS_INTERRUPTED=true
|
||||
BATS_ERROR_STATUS=130
|
||||
BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=true
|
||||
exit $BATS_ERROR_STATUS
|
||||
}
|
37
extras/portable/test/bats/lib/bats-core/validator.bash
Normal file
37
extras/portable/test/bats/lib/bats-core/validator.bash
Normal file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
bats_test_count_validator() {
|
||||
trap '' INT # continue forwarding
|
||||
header_pattern='[0-9]+\.\.[0-9]+'
|
||||
IFS= read -r header
|
||||
# repeat the header
|
||||
printf "%s\n" "$header"
|
||||
|
||||
# if we detect a TAP plan
|
||||
if [[ "$header" =~ $header_pattern ]]; then
|
||||
# extract the number of tests ...
|
||||
local expected_number_of_tests="${header:3}"
|
||||
# ... count the actual number of [not ] oks...
|
||||
local actual_number_of_tests=0
|
||||
while IFS= read -r line; do
|
||||
# forward line
|
||||
printf "%s\n" "$line"
|
||||
case "$line" in
|
||||
'ok '*)
|
||||
(( ++actual_number_of_tests ))
|
||||
;;
|
||||
'not ok'*)
|
||||
(( ++actual_number_of_tests ))
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# ... and error if they are not the same
|
||||
if [[ "${actual_number_of_tests}" != "${expected_number_of_tests}" ]]; then
|
||||
printf '# bats warning: Executed %s instead of expected %s tests\n' "$actual_number_of_tests" "$expected_number_of_tests"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# forward output unchanged
|
||||
cat
|
||||
fi
|
||||
}
|
35
extras/portable/test/bats/lib/bats-core/warnings.bash
Normal file
35
extras/portable/test/bats/lib/bats-core/warnings.bash
Normal file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# shellcheck source=lib/bats-core/tracing.bash
|
||||
source "$BATS_ROOT/lib/bats-core/tracing.bash"
|
||||
|
||||
BATS_WARNING_SHORT_DESCS=(
|
||||
# to start with 1
|
||||
'PADDING'
|
||||
# see issue #578 for context
|
||||
"\`run\`'s command \`%s\` exited with code 127, indicating 'Command not found'. Use run's return code checks, e.g. \`run -127\`, to fix this message."
|
||||
"%s requires at least BATS_VERSION=%s. Use \`bats_require_minimum_version %s\` to fix this message."
|
||||
)
|
||||
|
||||
# generate a warning report for the parent call's call site
|
||||
bats_generate_warning() { # <warning number> [<printf args for warning string>...]
|
||||
local warning_number="$1" padding="00"
|
||||
shift
|
||||
if [[ $warning_number =~ [0-9]+ ]] && ((warning_number < ${#BATS_WARNING_SHORT_DESCS[@]} )); then
|
||||
{
|
||||
printf "BW%s: ${BATS_WARNING_SHORT_DESCS[$warning_number]}\n" "${padding:${#warning_number}}${warning_number}" "$@"
|
||||
bats_capture_stack_trace
|
||||
BATS_STACK_TRACE_PREFIX=' ' bats_print_stack_trace "${BATS_DEBUG_LAST_STACK_TRACE[@]}"
|
||||
} >> "$BATS_WARNING_FILE" 2>&3
|
||||
else
|
||||
printf "Invalid Bats warning number '%s'. It must be an integer between 1 and %d." "$warning_number" "$((${#BATS_WARNING_SHORT_DESCS[@]} - 1))" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# generate a warning if the BATS_GUARANTEED_MINIMUM_VERSION is not high enough
|
||||
bats_warn_minimum_guaranteed_version() { # <feature> <minimum required version>
|
||||
if bats_version_lt "$BATS_GUARANTEED_MINIMUM_VERSION" "$2"; then
|
||||
bats_generate_warning 2 "$1" "$2" "$2"
|
||||
fi
|
||||
}
|
467
extras/portable/test/bats/libexec/bats-core/bats
Executable file
467
extras/portable/test/bats/libexec/bats-core/bats
Executable file
@ -0,0 +1,467 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
export BATS_VERSION='1.7.0'
|
||||
VALID_FORMATTERS="pretty, junit, tap, tap13"
|
||||
|
||||
version() {
|
||||
printf 'Bats %s\n' "$BATS_VERSION"
|
||||
}
|
||||
|
||||
abort() {
|
||||
local print_usage=1
|
||||
if [[ ${1:-} == --no-print-usage ]]; then
|
||||
print_usage=
|
||||
shift
|
||||
fi
|
||||
printf 'Error: %s\n' "$1" >&2
|
||||
if [[ -n $print_usage ]]; then
|
||||
usage >&2
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
usage() {
|
||||
local cmd="${0##*/}"
|
||||
local line
|
||||
|
||||
cat <<HELP_TEXT_HEADER
|
||||
Usage: ${cmd} [OPTIONS] <tests>
|
||||
${cmd} [-h | -v]
|
||||
|
||||
HELP_TEXT_HEADER
|
||||
|
||||
cat <<'HELP_TEXT_BODY'
|
||||
<tests> is the path to a Bats test file, or the path to a directory
|
||||
containing Bats test files (ending with ".bats")
|
||||
|
||||
-c, --count Count test cases without running any tests
|
||||
--code-quote-style <style>
|
||||
A two character string of code quote delimiters
|
||||
or 'custom' which requires setting $BATS_BEGIN_CODE_QUOTE and
|
||||
$BATS_END_CODE_QUOTE. Can also be set via $BATS_CODE_QUOTE_STYLE
|
||||
-f, --filter <regex> Only run tests that match the regular expression
|
||||
--filter-status <status> Only run tests with the given status in the last completed (no CTRL+C/SIGINT) run.
|
||||
Valid <status> values are:
|
||||
failed - runs tests that failed or were not present in the last run
|
||||
missed - runs tests that were not present in the last run
|
||||
-F, --formatter <type> Switch between formatters: pretty (default),
|
||||
tap (default w/o term), tap13, junit, /<absolute path to formatter>
|
||||
--gather-test-outputs-in <directory>
|
||||
Gather the output of failing *and* passing tests
|
||||
as files in directory (if existing, must be empty)
|
||||
-h, --help Display this help message
|
||||
-j, --jobs <jobs> Number of parallel jobs (requires GNU parallel)
|
||||
--no-tempdir-cleanup Preserve test output temporary directory
|
||||
--no-parallelize-across-files
|
||||
Serialize test file execution instead of running
|
||||
them in parallel (requires --jobs >1)
|
||||
--no-parallelize-within-files
|
||||
Serialize test execution within files instead of
|
||||
running them in parallel (requires --jobs >1)
|
||||
--report-formatter <type> Switch between reporters (same options as --formatter)
|
||||
-o, --output <dir> Directory to write report files (must exist)
|
||||
-p, --pretty Shorthand for "--formatter pretty"
|
||||
--print-output-on-failure Automatically print the value of `$output` on failed tests
|
||||
-r, --recursive Include tests in subdirectories
|
||||
--show-output-of-passing-tests
|
||||
Print output of passing tests
|
||||
-t, --tap Shorthand for "--formatter tap"
|
||||
-T, --timing Add timing information to tests
|
||||
-x, --trace Print test commands as they are executed (like `set -x`)
|
||||
--verbose-run Make `run` print `$output` by default
|
||||
-v, --version Display the version number
|
||||
|
||||
For more information, see https://github.com/bats-core/bats-core
|
||||
HELP_TEXT_BODY
|
||||
}
|
||||
|
||||
expand_path() {
|
||||
local path="${1%/}"
|
||||
local dirname="${path%/*}"
|
||||
local result="$2"
|
||||
|
||||
if [[ "$dirname" == "$path" ]]; then
|
||||
dirname="$PWD"
|
||||
else
|
||||
cd "$dirname"
|
||||
dirname="$PWD"
|
||||
cd "$OLDPWD"
|
||||
fi
|
||||
printf -v "$result" '%s/%s' "$dirname" "${path##*/}"
|
||||
}
|
||||
|
||||
BATS_LIBEXEC="$(cd "$(dirname "$(bats_readlinkf "${BASH_SOURCE[0]}")")"; pwd)"
|
||||
export BATS_LIBEXEC
|
||||
export BATS_CWD="$PWD"
|
||||
export BATS_TEST_FILTER=
|
||||
export PATH="$BATS_LIBEXEC:$PATH"
|
||||
export BATS_ROOT_PID=$$
|
||||
export BATS_TMPDIR="${TMPDIR:-/tmp}"
|
||||
BATS_TMPDIR=${BATS_TMPDIR%/} # chop off trailing / to avoid duplication
|
||||
export BATS_RUN_TMPDIR=
|
||||
export BATS_GUARANTEED_MINIMUM_VERSION=0.0.0
|
||||
|
||||
if [[ ! -d "${BATS_TMPDIR}" ]];then
|
||||
printf "Error: BATS_TMPDIR (%s) does not exist or is not a directory" "${BATS_TMPDIR}" >&2
|
||||
exit 1
|
||||
elif [[ ! -w "${BATS_TMPDIR}" ]];then
|
||||
printf "Error: BATS_TMPDIR (%s) is not writable" "${BATS_TMPDIR}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
arguments=()
|
||||
|
||||
# Unpack single-character options bundled together, e.g. -cr, -pr.
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" =~ ^-[^-]. ]]; then
|
||||
index=1
|
||||
while option="${arg:$((index++)):1}"; do
|
||||
if [[ -z "$option" ]]; then
|
||||
break
|
||||
fi
|
||||
arguments+=("-$option")
|
||||
done
|
||||
else
|
||||
arguments+=("$arg")
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
set -- "${arguments[@]}"
|
||||
arguments=()
|
||||
|
||||
unset flags recursive formatter_flags
|
||||
flags=('--dummy-flag') # add a dummy flag to prevent unset variable errors on empty array expansion in old bash versions
|
||||
formatter_flags=('--dummy-flag') # add a dummy flag to prevent unset variable errors on empty array expansion in old bash versions
|
||||
formatter='tap'
|
||||
report_formatter=''
|
||||
recursive=
|
||||
setup_suite_file=''
|
||||
export BATS_TEMPDIR_CLEANUP=1
|
||||
output=
|
||||
if [[ -z "${CI:-}" && -t 0 && -t 1 ]] && command -v tput >/dev/null; then
|
||||
formatter='pretty'
|
||||
fi
|
||||
|
||||
while [[ "$#" -ne 0 ]]; do
|
||||
case "$1" in
|
||||
-h | --help)
|
||||
version
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-v | --version)
|
||||
version
|
||||
exit 0
|
||||
;;
|
||||
-c | --count)
|
||||
flags+=('-c')
|
||||
;;
|
||||
-f | --filter)
|
||||
shift
|
||||
flags+=('-f' "$1")
|
||||
;;
|
||||
-F | --formatter)
|
||||
shift
|
||||
# allow cat formatter to see extended output but don't advertise to users
|
||||
if [[ $1 =~ ^(pretty|junit|tap|tap13|cat|/.*)$ ]]; then
|
||||
formatter="$1"
|
||||
else
|
||||
printf "Unknown formatter '%s', valid options are %s\n" "$1" "${VALID_FORMATTERS}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--report-formatter)
|
||||
shift
|
||||
if [[ $1 =~ ^(pretty|junit|tap|tap13)$ ]]; then
|
||||
report_formatter="$1"
|
||||
else
|
||||
printf "Unknown report formatter '%s', valid options are %s\n" "$1" "${VALID_FORMATTERS}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-o | --output)
|
||||
shift
|
||||
output="$1"
|
||||
;;
|
||||
-p | --pretty)
|
||||
formatter='pretty'
|
||||
;;
|
||||
-j | --jobs)
|
||||
shift
|
||||
flags+=('-j' "$1")
|
||||
;;
|
||||
-r | --recursive)
|
||||
recursive=1
|
||||
;;
|
||||
-t | --tap)
|
||||
formatter='tap'
|
||||
;;
|
||||
-T | --timing)
|
||||
flags+=('-T')
|
||||
formatter_flags+=('-T')
|
||||
;;
|
||||
# this flag is now a no-op, as it is the parallel default
|
||||
--parallel-preserve-environment)
|
||||
;;
|
||||
--no-parallelize-across-files)
|
||||
flags+=("--no-parallelize-across-files")
|
||||
;;
|
||||
--no-parallelize-within-files)
|
||||
flags+=("--no-parallelize-within-files")
|
||||
;;
|
||||
--no-tempdir-cleanup)
|
||||
BATS_TEMPDIR_CLEANUP=''
|
||||
;;
|
||||
--tempdir) # for internal test consumption only!
|
||||
BATS_RUN_TMPDIR="$2"
|
||||
shift
|
||||
;;
|
||||
-x | --trace)
|
||||
flags+=(--trace)
|
||||
;;
|
||||
--print-output-on-failure)
|
||||
flags+=(--print-output-on-failure)
|
||||
;;
|
||||
--show-output-of-passing-tests)
|
||||
flags+=(--show-output-of-passing-tests)
|
||||
;;
|
||||
--verbose-run)
|
||||
flags+=(--verbose-run)
|
||||
;;
|
||||
--gather-test-outputs-in)
|
||||
shift
|
||||
output_dir="$1"
|
||||
if [ -d "$output_dir" ]; then
|
||||
if ! find "$output_dir" -mindepth 1 -exec false {} + 2>/dev/null; then
|
||||
abort --no-print-usage "Directory '$output_dir' must be empty for --gather-test-outputs-in"
|
||||
fi
|
||||
elif ! mkdir "$output_dir" 2>/dev/null; then
|
||||
abort --no-print-usage "Could not create '$output_dir' for --gather-test-outputs-in"
|
||||
fi
|
||||
flags+=(--gather-test-outputs-in "$output_dir")
|
||||
;;
|
||||
--setup-suite-file)
|
||||
shift
|
||||
setup_suite_file="$1"
|
||||
;;
|
||||
--code-quote-style)
|
||||
shift
|
||||
BATS_CODE_QUOTE_STYLE="$1"
|
||||
;;
|
||||
--filter-status)
|
||||
shift
|
||||
flags+=('--filter-status' "$1")
|
||||
;;
|
||||
-*)
|
||||
abort "Bad command line option '$1'"
|
||||
;;
|
||||
*)
|
||||
arguments+=("$1")
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ -n "${BATS_RUN_TMPDIR:-}" ]];then
|
||||
if [[ -d "$BATS_RUN_TMPDIR" ]]; then
|
||||
printf "Error: BATS_RUN_TMPDIR (%s) already exists\n" "$BATS_RUN_TMPDIR" >&2
|
||||
printf "Reusing old run directories can lead to unexpected results ... aborting!\n" >&2
|
||||
exit 1
|
||||
elif ! mkdir -p "$BATS_RUN_TMPDIR" ;then
|
||||
printf "Error: Failed to create BATS_RUN_TMPDIR (%s)\n" "$BATS_RUN_TMPDIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
elif ! BATS_RUN_TMPDIR=$(mktemp -d "${BATS_TMPDIR}/bats-run-XXXXXX");then
|
||||
printf "Error: Failed to create BATS_RUN_TMPDIR (%s) with mktemp\n" "${BATS_TMPDIR}/bats-run-XXXXXX" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export BATS_WARNING_FILE="${BATS_RUN_TMPDIR}/warnings.log"
|
||||
|
||||
bats_exit_trap() {
|
||||
if [[ -s "$BATS_WARNING_FILE" ]]; then
|
||||
local pre_cat='' post_cat=''
|
||||
if [[ $formatter == pretty ]]; then
|
||||
pre_cat=$'\x1B[31m'
|
||||
post_cat=$'\x1B[0m'
|
||||
fi
|
||||
printf "\nThe following warnings were encountered during tests:\n%s" "$pre_cat"
|
||||
cat "$BATS_WARNING_FILE"
|
||||
printf "%s" "$post_cat"
|
||||
fi >&2
|
||||
|
||||
if [[ -n "$BATS_TEMPDIR_CLEANUP" ]]; then
|
||||
rm -rf "$BATS_RUN_TMPDIR"
|
||||
else
|
||||
printf "BATS_RUN_TMPDIR: %s\n" "$BATS_RUN_TMPDIR" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
trap bats_exit_trap EXIT
|
||||
|
||||
if [[ "$formatter" != "tap" ]]; then
|
||||
flags+=('-x')
|
||||
fi
|
||||
|
||||
if [[ -n "$report_formatter" && "$report_formatter" != "tap" ]]; then
|
||||
flags+=('-x')
|
||||
fi
|
||||
|
||||
if [[ "$formatter" == "junit" ]]; then
|
||||
flags+=('-T')
|
||||
formatter_flags+=('--base-path' "${arguments[0]}")
|
||||
fi
|
||||
if [[ "$report_formatter" == "junit" ]]; then
|
||||
flags+=('-T')
|
||||
report_formatter_flags+=('--base-path' "${arguments[0]}")
|
||||
fi
|
||||
|
||||
if [[ "$formatter" == "pretty" ]]; then
|
||||
formatter_flags+=('--base-path' "${arguments[0]}")
|
||||
fi
|
||||
|
||||
# if we don't need to filter extended syntax, use the faster formatter
|
||||
if [[ "$formatter" == tap && -z "$report_formatter" ]]; then
|
||||
formatter="cat"
|
||||
fi
|
||||
|
||||
bats_check_formatter() { # <formatter-path>
|
||||
local -r formatter="$1"
|
||||
if [[ ! -f "$formatter" ]]; then
|
||||
printf "ERROR: Formatter '%s' is not readable!\n" "$formatter"
|
||||
exit 1
|
||||
elif [[ ! -x "$formatter" ]]; then
|
||||
printf "ERROR: Formatter '%s' is not executable!\n" "$formatter"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ $formatter == /* ]]; then # absolute paths are direct references to formatters
|
||||
bats_check_formatter "$formatter"
|
||||
interpolated_formatter="$formatter"
|
||||
else
|
||||
interpolated_formatter="bats-format-${formatter}"
|
||||
fi
|
||||
|
||||
if [[ "${#arguments[@]}" -eq 0 ]]; then
|
||||
abort 'Must specify at least one <test>'
|
||||
fi
|
||||
|
||||
if [[ -n "$report_formatter" ]]; then
|
||||
# default to the current directory for output
|
||||
if [[ -z "$output" ]]; then
|
||||
output=.
|
||||
fi
|
||||
# only set BATS_REPORT_FILENAME if none was given
|
||||
if [[ -z "${BATS_REPORT_FILENAME:-}" ]]; then
|
||||
case "$report_formatter" in
|
||||
tap|tap13)
|
||||
BATS_REPORT_FILE_NAME="report.tap"
|
||||
;;
|
||||
junit)
|
||||
BATS_REPORT_FILE_NAME="report.xml"
|
||||
;;
|
||||
*)
|
||||
BATS_REPORT_FILE_NAME="report.log"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $report_formatter == /* ]]; then # absolute paths are direct references to formatters
|
||||
bats_check_formatter "$report_formatter"
|
||||
interpolated_report_formatter="${report_formatter}"
|
||||
else
|
||||
interpolated_report_formatter="bats-format-${report_formatter}"
|
||||
fi
|
||||
|
||||
if [[ "${BATS_CODE_QUOTE_STYLE-BATS_CODE_QUOTE_STYLE_UNSET}" == BATS_CODE_QUOTE_STYLE_UNSET ]]; then
|
||||
BATS_CODE_QUOTE_STYLE="\`'"
|
||||
fi
|
||||
|
||||
case "${BATS_CODE_QUOTE_STYLE}" in
|
||||
??)
|
||||
BATS_BEGIN_CODE_QUOTE="${BATS_CODE_QUOTE_STYLE::1}"
|
||||
BATS_END_CODE_QUOTE="${BATS_CODE_QUOTE_STYLE:1:1}"
|
||||
export BATS_BEGIN_CODE_QUOTE BATS_END_CODE_QUOTE
|
||||
;;
|
||||
custom)
|
||||
if [[ ${BATS_BEGIN_CODE_QUOTE-BATS_BEGIN_CODE_QUOTE_UNSET} == BATS_BEGIN_CODE_QUOTE_UNSET
|
||||
|| ${BATS_END_CODE_QUOTE-BATS_BEGIN_CODE_QUOTE_UNSET} == BATS_BEGIN_CODE_QUOTE_UNSET ]]; then
|
||||
printf "ERROR: BATS_CODE_QUOTE_STYLE=custom requires BATS_BEGIN_CODE_QUOTE and BATS_END_CODE_QUOTE to be set\n" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
printf "ERROR: Unknown BATS_CODE_QUOTE_STYLE: %s\n" "$BATS_CODE_QUOTE_STYLE" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -n "$output" ]]; then
|
||||
if [[ ! -w "${output}" ]]; then
|
||||
abort "Output path ${output} is not writeable"
|
||||
fi
|
||||
export BATS_REPORT_OUTPUT_PATH="$output"
|
||||
fi
|
||||
|
||||
if [[ -n "$setup_suite_file" && ! -f "$setup_suite_file" ]]; then
|
||||
abort "--setup-suite-file $setup_suite_file does not exist!"
|
||||
fi
|
||||
|
||||
filenames=()
|
||||
for filename in "${arguments[@]}"; do
|
||||
expand_path "$filename" 'filename'
|
||||
|
||||
if [[ -z "$setup_suite_file" ]]; then
|
||||
if [[ -d "$filename" ]]; then
|
||||
dirname="$filename"
|
||||
else
|
||||
dirname="${filename%/*}"
|
||||
fi
|
||||
potential_setup_suite_file="$dirname/setup_suite.bash"
|
||||
if [[ -e "$potential_setup_suite_file" ]]; then
|
||||
setup_suite_file="$potential_setup_suite_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -d "$filename" ]]; then
|
||||
shopt -s nullglob
|
||||
if [[ "$recursive" -eq 1 ]]; then
|
||||
while IFS= read -r -d $'\0' file; do
|
||||
filenames+=("$file")
|
||||
done < <(find -L "$filename" -type f -name "*.${BATS_FILE_EXTENSION:-bats}" -print0 | sort -z)
|
||||
else
|
||||
for suite_filename in "$filename"/*."${BATS_FILE_EXTENSION:-bats}"; do
|
||||
filenames+=("$suite_filename")
|
||||
done
|
||||
fi
|
||||
shopt -u nullglob
|
||||
else
|
||||
filenames+=("$filename")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n "$setup_suite_file" ]]; then
|
||||
flags+=("--setup-suite-file" "$setup_suite_file")
|
||||
fi
|
||||
|
||||
# shellcheck source=lib/bats-core/validator.bash
|
||||
source "$BATS_ROOT/lib/bats-core/validator.bash"
|
||||
|
||||
trap 'BATS_INTERRUPTED=true' INT # let the lower levels handle the interruption
|
||||
|
||||
set -o pipefail execfail
|
||||
|
||||
if [[ -n "$report_formatter" ]]; then
|
||||
exec bats-exec-suite "${flags[@]}" "${filenames[@]}" | \
|
||||
tee >("$interpolated_report_formatter" "${report_formatter_flags[@]}" >"${BATS_REPORT_OUTPUT_PATH}/${BATS_REPORT_FILE_NAME}") | \
|
||||
bats_test_count_validator | \
|
||||
"$interpolated_formatter" "${formatter_flags[@]}"
|
||||
else
|
||||
exec bats-exec-suite "${flags[@]}" "${filenames[@]}" | \
|
||||
bats_test_count_validator | \
|
||||
"$interpolated_formatter" "${formatter_flags[@]}"
|
||||
fi
|
338
extras/portable/test/bats/libexec/bats-core/bats-exec-file
Executable file
338
extras/portable/test/bats/libexec/bats-core/bats-exec-file
Executable file
@ -0,0 +1,338 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eET
|
||||
|
||||
flags=('--dummy-flag')
|
||||
num_jobs=${BATS_NUMBER_OF_PARALLEL_JOBS:-1}
|
||||
extended_syntax=''
|
||||
BATS_TRACE_LEVEL="${BATS_TRACE_LEVEL:-0}"
|
||||
declare -r BATS_RETRY_RETURN_CODE=126
|
||||
export BATS_TEST_RETRIES=0 # no retries by default
|
||||
|
||||
while [[ "$#" -ne 0 ]]; do
|
||||
case "$1" in
|
||||
-j)
|
||||
shift
|
||||
num_jobs="$1"
|
||||
;;
|
||||
-T)
|
||||
flags+=('-T')
|
||||
;;
|
||||
-x)
|
||||
flags+=('-x')
|
||||
extended_syntax=1
|
||||
;;
|
||||
--no-parallelize-within-files)
|
||||
# use singular to allow for users to override in file
|
||||
BATS_NO_PARALLELIZE_WITHIN_FILE=1
|
||||
;;
|
||||
--dummy-flag)
|
||||
;;
|
||||
--trace)
|
||||
flags+=('--trace')
|
||||
;;
|
||||
--print-output-on-failure)
|
||||
flags+=(--print-output-on-failure)
|
||||
;;
|
||||
--show-output-of-passing-tests)
|
||||
flags+=(--show-output-of-passing-tests)
|
||||
;;
|
||||
--verbose-run)
|
||||
flags+=(--verbose-run)
|
||||
;;
|
||||
--gather-test-outputs-in)
|
||||
shift
|
||||
flags+=(--gather-test-outputs-in "$1")
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
filename="$1"
|
||||
TESTS_FILE="$2"
|
||||
|
||||
if [[ ! -f "$filename" ]]; then
|
||||
printf 'Testfile "%s" not found\n' "$filename" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export BATS_TEST_FILENAME="$filename"
|
||||
|
||||
# shellcheck source=lib/bats-core/preprocessing.bash
|
||||
# shellcheck disable=SC2153
|
||||
source "$BATS_ROOT/lib/bats-core/preprocessing.bash"
|
||||
|
||||
bats_run_setup_file() {
|
||||
# shellcheck source=lib/bats-core/tracing.bash
|
||||
# shellcheck disable=SC2153
|
||||
source "$BATS_ROOT/lib/bats-core/tracing.bash"
|
||||
# shellcheck source=lib/bats-core/test_functions.bash
|
||||
# shellcheck disable=SC2153
|
||||
source "$BATS_ROOT/lib/bats-core/test_functions.bash"
|
||||
|
||||
exec 3<&1
|
||||
|
||||
# these are defined only to avoid errors when referencing undefined variables down the line
|
||||
# shellcheck disable=2034
|
||||
BATS_TEST_NAME= # used in tracing.bash
|
||||
# shellcheck disable=2034
|
||||
BATS_TEST_COMPLETED= # used in tracing.bash
|
||||
|
||||
BATS_SOURCE_FILE_COMPLETED=
|
||||
BATS_SETUP_FILE_COMPLETED=
|
||||
BATS_TEARDOWN_FILE_COMPLETED=
|
||||
# shellcheck disable=2034
|
||||
BATS_ERROR_STATUS= # used in tracing.bash
|
||||
touch "$BATS_OUT"
|
||||
bats_setup_tracing
|
||||
trap 'bats_file_teardown_trap' EXIT
|
||||
|
||||
local status=0
|
||||
# get the setup_file/teardown_file functions for this file (if it has them)
|
||||
# shellcheck disable=SC1090
|
||||
source "$BATS_TEST_SOURCE" >>"$BATS_OUT" 2>&1
|
||||
|
||||
BATS_SOURCE_FILE_COMPLETED=1
|
||||
|
||||
setup_file >>"$BATS_OUT" 2>&1
|
||||
|
||||
BATS_SETUP_FILE_COMPLETED=1
|
||||
}
|
||||
|
||||
bats_run_teardown_file() {
|
||||
# avoid running the therdown trap due to errors in teardown_file
|
||||
trap 'bats_file_exit_trap' EXIT
|
||||
# rely on bats_error_trap to catch failures
|
||||
teardown_file >>"$BATS_OUT" 2>&1
|
||||
|
||||
BATS_TEARDOWN_FILE_COMPLETED=1
|
||||
}
|
||||
|
||||
bats_file_teardown_trap() {
|
||||
bats_run_teardown_file
|
||||
bats_file_exit_trap
|
||||
}
|
||||
|
||||
# shellcheck source=lib/bats-core/common.bash
|
||||
source "$BATS_ROOT/lib/bats-core/common.bash"
|
||||
|
||||
bats_file_exit_trap() {
|
||||
trap - ERR EXIT
|
||||
local failure_reason
|
||||
local -i failure_test_index=$(( BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE + 1 ))
|
||||
if [[ -z "$BATS_SETUP_FILE_COMPLETED" || -z "$BATS_TEARDOWN_FILE_COMPLETED" ]]; then
|
||||
if [[ -z "$BATS_SETUP_FILE_COMPLETED" ]]; then
|
||||
failure_reason='setup_file'
|
||||
elif [[ -z "$BATS_TEARDOWN_FILE_COMPLETED" ]]; then
|
||||
failure_reason='teardown_file'
|
||||
failure_test_index=$(( BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE + ${#tests_to_run[@]} + 1 ))
|
||||
elif [[ -z "$BATS_SOURCE_FILE_COMPLETED" ]]; then
|
||||
failure_reason='source'
|
||||
else
|
||||
failure_reason='unknown internal'
|
||||
fi
|
||||
printf "not ok %d %s\n" "$failure_test_index" "$failure_reason failed" >&3
|
||||
local stack_trace
|
||||
bats_get_failure_stack_trace stack_trace
|
||||
bats_print_stack_trace "${stack_trace[@]}" >&3
|
||||
bats_print_failed_command "${stack_trace[@]}" >&3
|
||||
bats_prefix_lines_for_tap_output < "$BATS_OUT" | bats_replace_filename >&3
|
||||
rm -rf "$BATS_OUT"
|
||||
bats_exec_file_status=1
|
||||
fi
|
||||
exit $bats_exec_file_status
|
||||
}
|
||||
|
||||
function setup_file() {
|
||||
return 0
|
||||
}
|
||||
|
||||
function teardown_file() {
|
||||
return 0
|
||||
}
|
||||
|
||||
bats_forward_output_of_parallel_test() {
|
||||
local test_number_in_suite=$1
|
||||
local status=0
|
||||
wait "$(cat "$output_folder/$test_number_in_suite/pid")" || status=1
|
||||
cat "$output_folder/$test_number_in_suite/stdout"
|
||||
cat "$output_folder/$test_number_in_suite/stderr" >&2
|
||||
return $status
|
||||
}
|
||||
|
||||
bats_is_next_parallel_test_finished() {
|
||||
local PID
|
||||
# get the pid of the next potentially finished test
|
||||
PID=$(cat "$output_folder/$(( test_number_in_suite_of_last_finished_test + 1 ))/pid")
|
||||
# try to send a signal to this process
|
||||
# if it fails, the process exited,
|
||||
# if it succeeds, the process is still running
|
||||
if kill -0 "$PID" 2>/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# prints output from all tests in the order they were started
|
||||
# $1 == "blocking": wait for a test to finish before printing
|
||||
# != "blocking": abort printing, when a test has not finished
|
||||
bats_forward_output_for_parallel_tests() {
|
||||
local status=0
|
||||
# was the next test already started?
|
||||
while (( test_number_in_suite_of_last_finished_test + 1 <= test_number_in_suite )); do
|
||||
# if we are okay with waiting or if the test has already been finished
|
||||
if [[ "$1" == "blocking" ]] || bats_is_next_parallel_test_finished ; then
|
||||
(( ++test_number_in_suite_of_last_finished_test ))
|
||||
bats_forward_output_of_parallel_test "$test_number_in_suite_of_last_finished_test" || status=$?
|
||||
else
|
||||
# non-blocking and the process has not finished -> abort the printing
|
||||
break
|
||||
fi
|
||||
done
|
||||
return $status
|
||||
}
|
||||
|
||||
bats_run_test_with_retries() { # <args>
|
||||
local status=0
|
||||
local should_try_again=1 try_number
|
||||
for ((try_number=1; should_try_again; ++try_number)); do
|
||||
if "$BATS_LIBEXEC/bats-exec-test" "$@" "$try_number"; then
|
||||
should_try_again=0
|
||||
else
|
||||
status=$?
|
||||
if ((status == BATS_RETRY_RETURN_CODE)); then
|
||||
should_try_again=1
|
||||
else
|
||||
should_try_again=0
|
||||
bats_exec_file_status=$status
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return $status
|
||||
}
|
||||
|
||||
bats_run_tests_in_parallel() {
|
||||
local output_folder="$BATS_RUN_TMPDIR/parallel_output"
|
||||
local status=0
|
||||
mkdir -p "$output_folder"
|
||||
# shellcheck source=lib/bats-core/semaphore.bash
|
||||
source "$BATS_ROOT/lib/bats-core/semaphore.bash"
|
||||
bats_semaphore_setup
|
||||
# the test_number_in_file is not yet incremented -> one before the next test to run
|
||||
local test_number_in_suite_of_last_finished_test="$BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE" # stores which test was printed last
|
||||
local test_number_in_file=0 test_number_in_suite=$BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE
|
||||
for test_name in "${tests_to_run[@]}"; do
|
||||
# Only handle non-empty lines
|
||||
if [[ $test_name ]]; then
|
||||
((++test_number_in_suite))
|
||||
((++test_number_in_file))
|
||||
mkdir -p "$output_folder/$test_number_in_suite"
|
||||
bats_semaphore_run "$output_folder/$test_number_in_suite" \
|
||||
bats_run_test_with_retries "${flags[@]}" "$filename" "$test_name" "$test_number_in_suite" "$test_number_in_file" \
|
||||
> "$output_folder/$test_number_in_suite/pid"
|
||||
fi
|
||||
# print results early to get interactive feedback
|
||||
bats_forward_output_for_parallel_tests non-blocking || status=1 # ignore if we did not finish yet
|
||||
done
|
||||
bats_forward_output_for_parallel_tests blocking || status=1
|
||||
return $status
|
||||
}
|
||||
|
||||
bats_read_tests_list_file() {
|
||||
local line_number=0
|
||||
tests_to_run=()
|
||||
# the global test number must be visible to traps -> not local
|
||||
local test_number_in_suite=''
|
||||
while read -r test_line; do
|
||||
# check if the line begins with filename
|
||||
# filename might contain some hard to parse characters,
|
||||
# use simple string operations to work around that issue
|
||||
if [[ "$filename" == "${test_line::${#filename}}" ]]; then
|
||||
# get the rest of the line without the separator \t
|
||||
test_name=${test_line:$((1 + ${#filename} ))}
|
||||
tests_to_run+=("$test_name")
|
||||
# save the first test's number for later iteration
|
||||
# this assumes that tests for a file are stored consecutive in the file!
|
||||
if [[ -z "$test_number_in_suite" ]]; then
|
||||
test_number_in_suite=$line_number
|
||||
fi
|
||||
fi
|
||||
((++line_number))
|
||||
done <"$TESTS_FILE"
|
||||
BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE="$test_number_in_suite"
|
||||
declare -ri BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE # mark readonly (cannot merge assignment, because value would be lost)
|
||||
}
|
||||
|
||||
bats_run_tests() {
|
||||
bats_exec_file_status=0
|
||||
|
||||
if [[ "$num_jobs" != 1 && "${BATS_NO_PARALLELIZE_WITHIN_FILE-False}" == False ]]; then
|
||||
export BATS_SEMAPHORE_NUMBER_OF_SLOTS="$num_jobs"
|
||||
bats_run_tests_in_parallel "$BATS_RUN_TMPDIR/parallel_output" || bats_exec_file_status=1
|
||||
else
|
||||
local test_number_in_suite=$BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE \
|
||||
test_number_in_file=0
|
||||
for test_name in "${tests_to_run[@]}"; do
|
||||
if [[ "${BATS_INTERRUPTED-NOTSET}" != NOTSET ]]; then
|
||||
bats_exec_file_status=130 # bash's code for SIGINT exits
|
||||
break
|
||||
fi
|
||||
# Only handle non-empty lines
|
||||
if [[ $test_name ]]; then
|
||||
((++test_number_in_suite))
|
||||
((++test_number_in_file))
|
||||
bats_run_test_with_retries "${flags[@]}" "$filename" "$test_name" \
|
||||
"$test_number_in_suite" "$test_number_in_file" || bats_exec_file_status=$?
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
bats_create_file_tempdirs() {
|
||||
local bats_files_tmpdir="${BATS_RUN_TMPDIR}/file"
|
||||
if ! mkdir -p "$bats_files_tmpdir"; then
|
||||
printf 'Failed to create %s\n' "$bats_files_tmpdir" >&2
|
||||
exit 1
|
||||
fi
|
||||
BATS_FILE_TMPDIR="$bats_files_tmpdir/${BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE?}"
|
||||
if ! mkdir "$BATS_FILE_TMPDIR"; then
|
||||
printf 'Failed to create BATS_FILE_TMPDIR=%s\n' "$BATS_FILE_TMPDIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
ln -s "$BATS_TEST_FILENAME" "$BATS_FILE_TMPDIR-$(basename "$BATS_TEST_FILENAME").source_file"
|
||||
export BATS_FILE_TMPDIR
|
||||
}
|
||||
|
||||
trap 'BATS_INTERRUPTED=true' INT
|
||||
|
||||
if [[ -n "$extended_syntax" ]]; then
|
||||
printf "suite %s\n" "$filename"
|
||||
fi
|
||||
|
||||
BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE=0 # predeclare as Bash 3.2 does not support declare -g
|
||||
bats_read_tests_list_file
|
||||
|
||||
# don't run potentially expensive setup/teardown_file
|
||||
# when there are no tests to run
|
||||
if [[ ${#tests_to_run[@]} -eq 0 ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# requires the test list to be read but not empty
|
||||
bats_create_file_tempdirs
|
||||
|
||||
bats_preprocess_source "$filename"
|
||||
|
||||
trap bats_interrupt_trap INT
|
||||
bats_run_setup_file
|
||||
|
||||
# during tests, we don't want to get backtraces from this level
|
||||
# just wait for the test to be interrupted and display their trace
|
||||
trap 'BATS_INTERRUPTED=true' INT
|
||||
bats_run_tests
|
||||
|
||||
trap bats_interrupt_trap INT
|
||||
bats_run_teardown_file
|
||||
|
||||
exit $bats_exec_file_status
|
359
extras/portable/test/bats/libexec/bats-core/bats-exec-suite
Executable file
359
extras/portable/test/bats/libexec/bats-core/bats-exec-suite
Executable file
@ -0,0 +1,359 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
count_only_flag=''
|
||||
filter=''
|
||||
num_jobs=${BATS_NUMBER_OF_PARALLEL_JOBS:-1}
|
||||
bats_no_parallelize_across_files=${BATS_NO_PARALLELIZE_ACROSS_FILES-}
|
||||
bats_no_parallelize_within_files=
|
||||
filter_status=''
|
||||
flags=('--dummy-flag') # add a dummy flag to prevent unset variable errors on empty array expansion in old bash versions
|
||||
setup_suite_file=''
|
||||
BATS_TRACE_LEVEL="${BATS_TRACE_LEVEL:-0}"
|
||||
|
||||
abort() {
|
||||
printf 'Error: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
while [[ "$#" -ne 0 ]]; do
|
||||
case "$1" in
|
||||
-c)
|
||||
count_only_flag=1
|
||||
;;
|
||||
-f)
|
||||
shift
|
||||
filter="$1"
|
||||
;;
|
||||
-j)
|
||||
shift
|
||||
num_jobs="$1"
|
||||
flags+=('-j' "$num_jobs")
|
||||
;;
|
||||
-T)
|
||||
flags+=('-T')
|
||||
;;
|
||||
-x)
|
||||
flags+=('-x')
|
||||
;;
|
||||
--no-parallelize-across-files)
|
||||
bats_no_parallelize_across_files=1
|
||||
;;
|
||||
--no-parallelize-within-files)
|
||||
bats_no_parallelize_within_files=1
|
||||
flags+=("--no-parallelize-within-files")
|
||||
;;
|
||||
--filter-status)
|
||||
shift
|
||||
filter_status="$1"
|
||||
;;
|
||||
--dummy-flag)
|
||||
;;
|
||||
--trace)
|
||||
flags+=('--trace')
|
||||
(( ++BATS_TRACE_LEVEL )) # avoid returning 0
|
||||
;;
|
||||
--print-output-on-failure)
|
||||
flags+=(--print-output-on-failure)
|
||||
;;
|
||||
--show-output-of-passing-tests)
|
||||
flags+=(--show-output-of-passing-tests)
|
||||
;;
|
||||
--verbose-run)
|
||||
flags+=(--verbose-run)
|
||||
;;
|
||||
--gather-test-outputs-in)
|
||||
shift
|
||||
flags+=(--gather-test-outputs-in "$1")
|
||||
;;
|
||||
--setup-suite-file)
|
||||
shift
|
||||
setup_suite_file="$1"
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ "$num_jobs" != 1 ]]; then
|
||||
if ! type -p parallel >/dev/null && [[ -z "$bats_no_parallelize_across_files" ]]; then
|
||||
abort "Cannot execute \"${num_jobs}\" jobs without GNU parallel"
|
||||
exit 1
|
||||
fi
|
||||
# shellcheck source=lib/bats-core/semaphore.bash
|
||||
source "${BATS_ROOT}/lib/bats-core/semaphore.bash"
|
||||
bats_semaphore_setup
|
||||
fi
|
||||
|
||||
# create a file that contains all (filtered) tests to run from all files
|
||||
TESTS_LIST_FILE="${BATS_RUN_TMPDIR}/test_list_file.txt"
|
||||
|
||||
bats_gather_tests() {
|
||||
all_tests=()
|
||||
for filename in "$@"; do
|
||||
if [[ ! -f "$filename" ]]; then
|
||||
abort "Test file \"${filename}\" does not exist"
|
||||
fi
|
||||
|
||||
test_names=()
|
||||
test_dupes=()
|
||||
while read -r line; do
|
||||
if [[ ! "$line" =~ ^bats_test_function\ ]]; then
|
||||
continue
|
||||
fi
|
||||
line="${line%$'\r'}"
|
||||
line="${line#* }"
|
||||
test_line=$(printf "%s\t%s" "$filename" "$line")
|
||||
all_tests+=("$test_line")
|
||||
printf "%s\n" "$test_line" >>"$TESTS_LIST_FILE"
|
||||
# avoid unbound variable errors on empty array expansion with old bash versions
|
||||
if [[ ${#test_names[@]} -gt 0 && " ${test_names[*]} " == *" $line "* ]]; then
|
||||
test_dupes+=("$line")
|
||||
continue
|
||||
fi
|
||||
test_names+=("$line")
|
||||
done < <(BATS_TEST_FILTER="$filter" bats-preprocess "$filename")
|
||||
|
||||
if [[ "${#test_dupes[@]}" -ne 0 ]]; then
|
||||
abort "Duplicate test name(s) in file \"${filename}\": ${test_dupes[*]}"
|
||||
fi
|
||||
done
|
||||
|
||||
test_count="${#all_tests[@]}"
|
||||
}
|
||||
|
||||
TEST_ROOT=${1-}
|
||||
TEST_ROOT=${TEST_ROOT%/*}
|
||||
BATS_RUN_LOGS_DIRECTORY="$TEST_ROOT/.bats/run-logs"
|
||||
if [[ ! -d "$BATS_RUN_LOGS_DIRECTORY" ]]; then
|
||||
if [[ -n "$filter_status" ]]; then
|
||||
printf "Error: --filter-status needs '%s/' to save failed tests. Please create this folder, add it to .gitignore and try again.\n" "$BATS_RUN_LOGS_DIRECTORY"
|
||||
exit 1
|
||||
else
|
||||
BATS_RUN_LOGS_DIRECTORY=
|
||||
fi
|
||||
# discard via sink instead of having a conditional later
|
||||
export BATS_RUNLOG_FILE='/dev/null'
|
||||
else
|
||||
# use UTC (-u) to avoid problems with TZ changes
|
||||
BATS_RUNLOG_DATE=$(date -u '+%Y-%m-%d %H:%M:%S UTC')
|
||||
export BATS_RUNLOG_FILE="$BATS_RUN_LOGS_DIRECTORY/${BATS_RUNLOG_DATE}.log"
|
||||
fi
|
||||
|
||||
bats_gather_tests "$@"
|
||||
|
||||
if [[ -n "$filter_status" ]]; then
|
||||
# shellcheck source=lib/bats-core/common.bash
|
||||
source "$BATS_ROOT/lib/bats-core/common.bash"
|
||||
case "$filter_status" in
|
||||
failed)
|
||||
bats_filter_test_by_status() { # <line>
|
||||
! bats_binary_search "$1" "passed_tests"
|
||||
}
|
||||
;;
|
||||
passed)
|
||||
bats_filter_test_by_status() {
|
||||
! bats_binary_search "$1" "failed_tests"
|
||||
}
|
||||
;;
|
||||
missed)
|
||||
bats_filter_test_by_status() {
|
||||
! bats_binary_search "$1" "failed_tests" && ! bats_binary_search "$1" "passed_tests"
|
||||
}
|
||||
;;
|
||||
*)
|
||||
printf "Error: Unknown value '%s' for --filter-status. Valid values are 'failed' and 'missed'.\n" "$filter_status">&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if IFS='' read -d $'\n' -r BATS_PREVIOUS_RUNLOG_FILE < <(ls -1r "$BATS_RUN_LOGS_DIRECTORY"); then
|
||||
BATS_PREVIOUS_RUNLOG_FILE="$BATS_RUN_LOGS_DIRECTORY/$BATS_PREVIOUS_RUNLOG_FILE"
|
||||
if [[ $BATS_PREVIOUS_RUNLOG_FILE == "$BATS_RUNLOG_FILE" ]]; then
|
||||
count=$(find "$BATS_RUN_LOGS_DIRECTORY" -name "$BATS_RUNLOG_DATE*" | wc -l)
|
||||
BATS_RUNLOG_FILE="$BATS_RUN_LOGS_DIRECTORY/${BATS_RUNLOG_DATE}-$count.log"
|
||||
fi
|
||||
failed_tests=()
|
||||
passed_tests=()
|
||||
# store tests that were already filtered out in the last run for the same filter reason
|
||||
last_filtered_tests=()
|
||||
i=0
|
||||
while read -rd $'\n' line; do
|
||||
((++i))
|
||||
case "$line" in
|
||||
"passed "*)
|
||||
passed_tests+=("${line#passed }")
|
||||
;;
|
||||
"failed "*)
|
||||
failed_tests+=("${line#failed }")
|
||||
;;
|
||||
"status-filtered $filter_status"*) # pick up tests that were filtered in the last round for the same status
|
||||
last_filtered_tests+=("${line#status-filtered "$filter_status" }")
|
||||
;;
|
||||
"status-filtered "*) # ignore other status-filtered lines
|
||||
;;
|
||||
"#"*) # allow for comments
|
||||
;;
|
||||
*)
|
||||
printf "Error: %s:%d: Invalid format: %s\n" "$BATS_PREVIOUS_RUNLOG_FILE" "$i" "$line" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done < <(sort "$BATS_PREVIOUS_RUNLOG_FILE")
|
||||
|
||||
filtered_tests=()
|
||||
for line in "${all_tests[@]}"; do
|
||||
if bats_filter_test_by_status "$line" && ! bats_binary_search "$line" last_filtered_tests; then
|
||||
printf "%s\n" "$line"
|
||||
filtered_tests+=("$line")
|
||||
else
|
||||
printf "status-filtered %s %s\n" "$filter_status" "$line" >> "$BATS_RUNLOG_FILE"
|
||||
fi
|
||||
done > "$TESTS_LIST_FILE"
|
||||
|
||||
# save filtered tests to exclude them again in next round
|
||||
for test_line in "${last_filtered_tests[@]}"; do
|
||||
printf "status-filtered %s %s\n" "$filter_status" "$test_line"
|
||||
done >> "$BATS_RUNLOG_FILE"
|
||||
|
||||
test_count="${#filtered_tests[@]}"
|
||||
if [[ ${#failed_tests[@]} -eq 0 && ${#filtered_tests[@]} -eq 0 ]]; then
|
||||
printf "There where no failed tests in the last recorded run.\n" >&2
|
||||
fi
|
||||
else
|
||||
printf "No recording of previous runs found. Running all tests!\n" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$count_only_flag" ]]; then
|
||||
printf '%d\n' "${test_count}"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [[ -n "$bats_no_parallelize_across_files" ]] && [[ ! "$num_jobs" -gt 1 ]]; then
|
||||
abort "The flag --no-parallelize-across-files requires at least --jobs 2"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "$bats_no_parallelize_within_files" ]] && [[ ! "$num_jobs" -gt 1 ]]; then
|
||||
abort "The flag --no-parallelize-across-files requires at least --jobs 2"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# only abort on the lowest levels
|
||||
trap 'BATS_INTERRUPTED=true' INT
|
||||
|
||||
bats_exec_suite_status=0
|
||||
printf '1..%d\n' "${test_count}"
|
||||
|
||||
# No point on continuing if there's no tests.
|
||||
if [[ "${test_count}" == 0 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
export BATS_SUITE_TMPDIR="${BATS_RUN_TMPDIR}/suite"
|
||||
if ! mkdir "$BATS_SUITE_TMPDIR"; then
|
||||
printf '%s\n' "Failed to create BATS_SUITE_TMPDIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Deduplicate filenames (without reordering) to avoid running duplicate tests n by n times.
|
||||
# (see https://github.com/bats-core/bats-core/issues/329)
|
||||
# If a file was specified multiple times, we already got it repeatedly in our TESTS_LIST_FILE.
|
||||
# Thus, it suffices to bats-exec-file it once to run all repeated tests on it.
|
||||
IFS=$'\n' read -d '' -r -a BATS_UNIQUE_TEST_FILENAMES < <(printf "%s\n" "$@"| nl | sort -k 2 | uniq -f 1 | sort -n | cut -f 2-) || true
|
||||
|
||||
# shellcheck source=lib/bats-core/tracing.bash
|
||||
source "$BATS_ROOT/lib/bats-core/tracing.bash"
|
||||
bats_setup_tracing
|
||||
|
||||
trap bats_suite_exit_trap EXIT
|
||||
|
||||
bats_suite_exit_trap() {
|
||||
if [[ -z "${BATS_SETUP_SUITE_COMPLETED}" || -z "${BATS_TEARDOWN_SUITE_COMPLETED}" ]]; then
|
||||
if [[ -z "${BATS_SETUP_SUITE_COMPLETED}" ]]; then
|
||||
printf "not ok 1 setup_suite\n"
|
||||
elif [[ -z "${BATS_TEARDOWN_SUITE_COMPLETED}" ]]; then
|
||||
printf "not ok %d teardown_suite\n" $((test_count+1))
|
||||
fi
|
||||
local stack_trace
|
||||
bats_get_failure_stack_trace stack_trace
|
||||
bats_print_stack_trace "${stack_trace[@]}"
|
||||
bats_print_failed_command "${stack_trace[@]}"
|
||||
bats_exec_suite_status=1
|
||||
fi
|
||||
if [[ ${BATS_INTERRUPTED-NOTSET} != NOTSET ]]; then
|
||||
printf "\n# Received SIGINT, aborting ...\n\n"
|
||||
fi
|
||||
|
||||
if [[ -d "$BATS_RUN_LOGS_DIRECTORY" && -n "${BATS_INTERRUPTED:-}" ]]; then
|
||||
# aborting a test run with CTRL+C does not save the runlog file
|
||||
rm "$BATS_RUNLOG_FILE"
|
||||
fi
|
||||
exit "$bats_exec_suite_status"
|
||||
}
|
||||
|
||||
bats_run_teardown_suite() {
|
||||
# avoid being called twice, in case this is not called through bats_teardown_suite_trap
|
||||
# but from the end of file
|
||||
trap bats_suite_exit_trap EXIT
|
||||
set -eET
|
||||
BATS_TEARDOWN_SUITE_COMPLETED=
|
||||
teardown_suite 2>&1
|
||||
BATS_TEARDOWN_SUITE_COMPLETED=1
|
||||
set +ET
|
||||
}
|
||||
|
||||
bats_teardown_suite_trap() {
|
||||
bats_run_teardown_suite
|
||||
bats_suite_exit_trap
|
||||
}
|
||||
|
||||
setup_suite() {
|
||||
:
|
||||
}
|
||||
|
||||
teardown_suite() {
|
||||
:
|
||||
}
|
||||
|
||||
trap bats_teardown_suite_trap EXIT
|
||||
|
||||
if [[ -n "$setup_suite_file" ]]; then
|
||||
setup_suite() {
|
||||
printf "%s does not define \`setup_suite()\`\n" "$setup_suite_file" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "$setup_suite_file"
|
||||
fi
|
||||
|
||||
set -eET
|
||||
BATS_SETUP_SUITE_COMPLETED=
|
||||
setup_suite 2>&1
|
||||
BATS_SETUP_SUITE_COMPLETED=1
|
||||
set +ET
|
||||
|
||||
if [[ "$num_jobs" -gt 1 ]] && [[ -z "$bats_no_parallelize_across_files" ]]; then
|
||||
# run files in parallel to get the maximum pool of parallel tasks
|
||||
# shellcheck disable=SC2086,SC2068
|
||||
# we need to handle the quoting of ${flags[@]} ourselves,
|
||||
# because parallel can only quote it as one
|
||||
parallel --keep-order --jobs "$num_jobs" bats-exec-file "$(printf "%q " "${flags[@]}")" "{}" "$TESTS_LIST_FILE" ::: "${BATS_UNIQUE_TEST_FILENAMES[@]}" 2>&1 || bats_exec_suite_status=1
|
||||
else
|
||||
for filename in "${BATS_UNIQUE_TEST_FILENAMES[@]}"; do
|
||||
if [[ "${BATS_INTERRUPTED-NOTSET}" != NOTSET ]]; then
|
||||
bats_exec_suite_status=130 # bash's code for SIGINT exits
|
||||
break
|
||||
fi
|
||||
bats-exec-file "${flags[@]}" "$filename" "${TESTS_LIST_FILE}" || bats_exec_suite_status=1
|
||||
done
|
||||
fi
|
||||
|
||||
set -eET
|
||||
bats_run_teardown_suite
|
||||
|
||||
exit "$bats_exec_suite_status"
|
231
extras/portable/test/bats/libexec/bats-core/bats-exec-test
Executable file
231
extras/portable/test/bats/libexec/bats-core/bats-exec-test
Executable file
@ -0,0 +1,231 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eET
|
||||
|
||||
# Variables used in other scripts.
|
||||
BATS_ENABLE_TIMING=''
|
||||
BATS_EXTENDED_SYNTAX=''
|
||||
BATS_TRACE_LEVEL="${BATS_TRACE_LEVEL:-0}"
|
||||
BATS_PRINT_OUTPUT_ON_FAILURE="${BATS_PRINT_OUTPUT_ON_FAILURE:-}"
|
||||
BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS="${BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS:-}"
|
||||
BATS_VERBOSE_RUN="${BATS_VERBOSE_RUN:-}"
|
||||
BATS_GATHER_TEST_OUTPUTS_IN="${BATS_GATHER_TEST_OUTPUTS_IN:-}"
|
||||
BATS_TEST_NAME_PREFIX="${BATS_TEST_NAME_PREFIX:-}"
|
||||
|
||||
while [[ "$#" -ne 0 ]]; do
|
||||
case "$1" in
|
||||
-T)
|
||||
BATS_ENABLE_TIMING='-T'
|
||||
;;
|
||||
-x)
|
||||
# shellcheck disable=SC2034
|
||||
BATS_EXTENDED_SYNTAX='-x'
|
||||
;;
|
||||
--dummy-flag)
|
||||
;;
|
||||
--trace)
|
||||
(( ++BATS_TRACE_LEVEL )) # avoid returning 0
|
||||
;;
|
||||
--print-output-on-failure)
|
||||
BATS_PRINT_OUTPUT_ON_FAILURE=1
|
||||
;;
|
||||
--show-output-of-passing-tests)
|
||||
BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS=1
|
||||
;;
|
||||
--verbose-run)
|
||||
BATS_VERBOSE_RUN=1
|
||||
;;
|
||||
--gather-test-outputs-in)
|
||||
shift
|
||||
BATS_GATHER_TEST_OUTPUTS_IN="$1"
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
export BATS_TEST_FILENAME="$1"
|
||||
export BATS_TEST_NAME="$2"
|
||||
export BATS_SUITE_TEST_NUMBER="$3"
|
||||
export BATS_TEST_NUMBER="$4"
|
||||
BATS_TEST_TRY_NUMBER="$5"
|
||||
|
||||
if [[ -z "$BATS_TEST_FILENAME" ]]; then
|
||||
printf 'usage: bats-exec-test <filename>\n' >&2
|
||||
exit 1
|
||||
elif [[ ! -f "$BATS_TEST_FILENAME" ]]; then
|
||||
printf 'bats: %s does not exist\n' "$BATS_TEST_FILENAME" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bats_create_test_tmpdirs() {
|
||||
local tests_tmpdir="${BATS_RUN_TMPDIR}/test"
|
||||
if ! mkdir -p "$tests_tmpdir"; then
|
||||
printf 'Failed to create: %s\n' "$tests_tmpdir" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BATS_TEST_TMPDIR="$tests_tmpdir/$BATS_SUITE_TEST_NUMBER"
|
||||
if ! mkdir "$BATS_TEST_TMPDIR"; then
|
||||
printf 'Failed to create BATS_TEST_TMPDIR%d: %s\n' "$BATS_TEST_TRY_NUMBER" "$BATS_TEST_TMPDIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf "%s\n" "$BATS_TEST_NAME" > "$BATS_TEST_TMPDIR.name"
|
||||
|
||||
export BATS_TEST_TMPDIR
|
||||
}
|
||||
|
||||
# load the test helper functions like `load` or `run` that are needed to run a (preprocessed) .bats file without bash errors
|
||||
# shellcheck source=lib/bats-core/test_functions.bash disable=SC2153
|
||||
source "$BATS_ROOT/lib/bats-core/test_functions.bash"
|
||||
# shellcheck source=lib/bats-core/tracing.bash disable=SC2153
|
||||
source "$BATS_ROOT/lib/bats-core/tracing.bash"
|
||||
|
||||
bats_teardown_trap() {
|
||||
bats_check_status_from_trap
|
||||
local bats_teardown_trap_status=0
|
||||
# mark the start of this function to distinguish where skip is called
|
||||
# parameter 1 will signify the reason why this function was called
|
||||
# this is used to identify when this is called as exit trap function
|
||||
BATS_TEARDOWN_STARTED=${1:-1}
|
||||
teardown >>"$BATS_OUT" 2>&1 || bats_teardown_trap_status="$?"
|
||||
|
||||
if [[ $bats_teardown_trap_status -eq 0 ]]; then
|
||||
BATS_TEARDOWN_COMPLETED=1
|
||||
elif [[ -n "$BATS_TEST_COMPLETED" ]]; then
|
||||
BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=1
|
||||
BATS_ERROR_STATUS="$bats_teardown_trap_status"
|
||||
fi
|
||||
|
||||
bats_exit_trap
|
||||
}
|
||||
|
||||
# shellcheck source=lib/bats-core/common.bash
|
||||
source "$BATS_ROOT/lib/bats-core/common.bash"
|
||||
|
||||
bats_exit_trap() {
|
||||
local status
|
||||
local skipped=''
|
||||
trap - ERR EXIT
|
||||
|
||||
if [[ -n "$BATS_TEST_SKIPPED" ]]; then
|
||||
skipped=' # skip'
|
||||
if [[ "$BATS_TEST_SKIPPED" != '1' ]]; then
|
||||
skipped+=" $BATS_TEST_SKIPPED"
|
||||
fi
|
||||
fi
|
||||
|
||||
BATS_TEST_TIME=''
|
||||
if [[ -z "${skipped}" && -n "$BATS_ENABLE_TIMING" ]]; then
|
||||
BATS_TEST_TIME=" in "$(( $(get_mills_since_epoch) - BATS_TEST_START_TIME ))"ms"
|
||||
fi
|
||||
|
||||
local print_bats_out="${BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS}"
|
||||
|
||||
local should_retry=''
|
||||
if [[ -z "$BATS_TEST_COMPLETED" || -z "$BATS_TEARDOWN_COMPLETED" || "${BATS_INTERRUPTED-NOTSET}" != NOTSET ]]; then
|
||||
if [[ "$BATS_ERROR_STATUS" -eq 0 ]]; then
|
||||
# For some versions of bash, `$?` may not be set properly for some error
|
||||
# conditions before triggering the EXIT trap directly (see #72 and #81).
|
||||
# Thanks to the `BATS_TEARDOWN_COMPLETED` signal, this will pinpoint such
|
||||
# errors if they happen during `teardown()` when `bats_perform_test` calls
|
||||
# `bats_teardown_trap` directly after the test itself passes.
|
||||
#
|
||||
# If instead the test fails, and the `teardown()` error happens while
|
||||
# `bats_teardown_trap` runs as the EXIT trap, the test will fail with no
|
||||
# output, since there's no way to reach the `bats_exit_trap` call.
|
||||
BATS_ERROR_STATUS=1
|
||||
fi
|
||||
if bats_should_retry_test; then
|
||||
should_retry=1
|
||||
status=126 # signify retry
|
||||
rm -r "$BATS_TEST_TMPDIR" # clean up for retry
|
||||
else
|
||||
printf 'not ok %d %s\n' "$BATS_SUITE_TEST_NUMBER" "${BATS_TEST_NAME_PREFIX:-}${BATS_TEST_DESCRIPTION}${BATS_TEST_TIME}" >&3
|
||||
local stack_trace
|
||||
bats_get_failure_stack_trace stack_trace
|
||||
bats_print_stack_trace "${stack_trace[@]}" >&3
|
||||
bats_print_failed_command "${stack_trace[@]}" >&3
|
||||
|
||||
if [[ $BATS_PRINT_OUTPUT_ON_FAILURE && -n "${output:-}" ]]; then
|
||||
printf "Last output:\n%s\n" "$output" >> "$BATS_OUT"
|
||||
fi
|
||||
|
||||
print_bats_out=1
|
||||
status=1
|
||||
local state=failed
|
||||
fi
|
||||
else
|
||||
printf 'ok %d %s%s\n' "$BATS_SUITE_TEST_NUMBER" "${BATS_TEST_NAME_PREFIX:-}${BATS_TEST_DESCRIPTION}${BATS_TEST_TIME}" \
|
||||
"$skipped" >&3
|
||||
status=0
|
||||
local state=passed
|
||||
fi
|
||||
|
||||
if [[ -z "$should_retry" ]]; then
|
||||
printf "%s %s\t%s\n" "$state" "$BATS_TEST_FILENAME" "$BATS_TEST_NAME" >> "$BATS_RUNLOG_FILE"
|
||||
|
||||
if [[ $print_bats_out ]]; then
|
||||
bats_prefix_lines_for_tap_output < "$BATS_OUT" | bats_replace_filename >&3
|
||||
fi
|
||||
fi
|
||||
if [[ $BATS_GATHER_TEST_OUTPUTS_IN ]]; then
|
||||
local try_suffix=
|
||||
if [[ -n "$should_retry" ]]; then
|
||||
try_suffix="-try$BATS_TEST_TRY_NUMBER"
|
||||
fi
|
||||
cp "$BATS_OUT" "$BATS_GATHER_TEST_OUTPUTS_IN/$BATS_SUITE_TEST_NUMBER$try_suffix-$BATS_TEST_DESCRIPTION.log"
|
||||
fi
|
||||
rm -f "$BATS_OUT"
|
||||
exit "$status"
|
||||
}
|
||||
|
||||
get_mills_since_epoch() {
|
||||
local ms_since_epoch
|
||||
ms_since_epoch=$(date +%s%N)
|
||||
if [[ "$ms_since_epoch" == *N || "${#ms_since_epoch}" -lt 19 ]]; then
|
||||
ms_since_epoch=$(( $(date +%s) * 1000 ))
|
||||
else
|
||||
ms_since_epoch=$(( ms_since_epoch / 1000000 ))
|
||||
fi
|
||||
|
||||
printf "%d\n" "$ms_since_epoch"
|
||||
}
|
||||
|
||||
bats_perform_test() {
|
||||
if ! declare -F "$BATS_TEST_NAME" &>/dev/null; then
|
||||
local quoted_test_name
|
||||
bats_quote_code quoted_test_name "$BATS_TEST_NAME"
|
||||
printf "bats: unknown test name %s\n" "$quoted_test_name" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BATS_TEST_COMPLETED=
|
||||
BATS_TEST_SKIPPED=
|
||||
BATS_TEARDOWN_COMPLETED=
|
||||
BATS_ERROR_STATUS=
|
||||
bats_setup_tracing
|
||||
# mark this call as trap call
|
||||
trap 'bats_teardown_trap as-exit-trap' EXIT
|
||||
|
||||
BATS_TEST_START_TIME=$(get_mills_since_epoch)
|
||||
"$BATS_TEST_NAME" >>"$BATS_OUT" 2>&1 4>&1
|
||||
|
||||
BATS_TEST_COMPLETED=1
|
||||
trap 'bats_exit_trap' EXIT
|
||||
bats_teardown_trap "" # pass empty parameter to signify call outside trap
|
||||
}
|
||||
|
||||
trap bats_interrupt_trap INT
|
||||
|
||||
# shellcheck source=lib/bats-core/preprocessing.bash
|
||||
source "$BATS_ROOT/lib/bats-core/preprocessing.bash"
|
||||
|
||||
exec 3<&1
|
||||
|
||||
bats_create_test_tmpdirs
|
||||
# Run the given test.
|
||||
bats_evaluate_preprocessed_source
|
||||
bats_perform_test
|
6
extras/portable/test/bats/libexec/bats-core/bats-format-cat
Executable file
6
extras/portable/test/bats/libexec/bats-core/bats-format-cat
Executable file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
trap '' INT
|
||||
|
||||
cat
|
251
extras/portable/test/bats/libexec/bats-core/bats-format-junit
Executable file
251
extras/portable/test/bats/libexec/bats-core/bats-format-junit
Executable file
@ -0,0 +1,251 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# shellcheck source=lib/bats-core/formatter.bash
|
||||
source "$BATS_ROOT/lib/bats-core/formatter.bash"
|
||||
|
||||
BASE_PATH=.
|
||||
|
||||
|
||||
while [[ "$#" -ne 0 ]]; do
|
||||
case "$1" in
|
||||
--base-path)
|
||||
shift
|
||||
normalize_base_path BASE_PATH "$1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
init_suite() {
|
||||
suite_test_exec_time=0
|
||||
# since we have to print the suite header before its contents but we don't know the contents before the header,
|
||||
# we have to buffer the contents
|
||||
_suite_buffer=""
|
||||
test_result_state="" # declare for the first flush, when no test has been encountered
|
||||
}
|
||||
|
||||
_buffer_log=
|
||||
init_file() {
|
||||
file_count=0
|
||||
file_failures=0
|
||||
file_skipped=0
|
||||
file_exec_time=0
|
||||
test_exec_time=0
|
||||
_buffer=""
|
||||
_buffer_log=""
|
||||
_system_out_log=""
|
||||
test_result_state="" # mark that no test has run in this file so far
|
||||
}
|
||||
|
||||
host() {
|
||||
local hostname="${HOST:-}"
|
||||
[[ -z "$hostname" ]] && hostname="${HOSTNAME:-}"
|
||||
[[ -z "$hostname" ]] && hostname="$(uname -n)"
|
||||
[[ -z "$hostname" ]] && hostname="$(hostname -f)"
|
||||
|
||||
echo "$hostname"
|
||||
}
|
||||
|
||||
# convert $1 (time in milliseconds) to seconds
|
||||
milliseconds_to_seconds() {
|
||||
# we cannot rely on having bc for this calculation
|
||||
full_seconds=$(($1 / 1000))
|
||||
remaining_milliseconds=$(($1 % 1000))
|
||||
if [[ $remaining_milliseconds -eq 0 ]]; then
|
||||
printf "%d" "$full_seconds"
|
||||
else
|
||||
printf "%d.%03d" "$full_seconds" "$remaining_milliseconds"
|
||||
fi
|
||||
}
|
||||
|
||||
suite_header() {
|
||||
printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
||||
<testsuites time=\"%s\">\n" "$(milliseconds_to_seconds "${suite_test_exec_time}")"
|
||||
}
|
||||
|
||||
file_header() {
|
||||
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%S")
|
||||
printf "<testsuite name=\"%s\" tests=\"%s\" failures=\"%s\" errors=\"0\" skipped=\"%s\" time=\"%s\" timestamp=\"%s\" hostname=\"%s\">\n" \
|
||||
"$(xml_escape "${class}")" "${file_count}" "${file_failures}" "${file_skipped}" "$(milliseconds_to_seconds "${file_exec_time}")" "${timestamp}" "$(host)"
|
||||
}
|
||||
|
||||
file_footer() {
|
||||
printf "</testsuite>\n"
|
||||
}
|
||||
|
||||
suite_footer() {
|
||||
printf "</testsuites>\n"
|
||||
}
|
||||
|
||||
print_test_case() {
|
||||
if [[ "$test_result_state" == ok && -z "$_system_out_log" && -z "$_buffer_log" ]]; then
|
||||
# pass and no output can be shortened
|
||||
printf " <testcase classname=\"%s\" name=\"%s\" time=\"%s\" />\n" "$(xml_escape "${class}")" "$(xml_escape "${name}")" "$(milliseconds_to_seconds "${test_exec_time}")"
|
||||
else
|
||||
printf " <testcase classname=\"%s\" name=\"%s\" time=\"%s\">\n" "$(xml_escape "${class}")" "$(xml_escape "${name}")" "$(milliseconds_to_seconds "${test_exec_time}")"
|
||||
if [[ -n "$_system_out_log" ]]; then
|
||||
printf " <system-out>%s</system-out>\n" "$(xml_escape "${_system_out_log}")"
|
||||
fi
|
||||
if [[ -n "$_buffer_log" || "$test_result_state" == not_ok ]]; then
|
||||
printf " <failure type=\"failure\">%s</failure>\n" "$(xml_escape "${_buffer_log}")"
|
||||
fi
|
||||
if [[ "$test_result_state" == skipped ]]; then
|
||||
printf " <skipped>%s</skipped>\n" "$(xml_escape "$test_skip_message")"
|
||||
fi
|
||||
printf " </testcase>\n"
|
||||
fi
|
||||
}
|
||||
|
||||
xml_escape() {
|
||||
output=${1//&/&}
|
||||
output=${output//</<}
|
||||
output=${output//>/>}
|
||||
output=${output//'"'/"}
|
||||
output=${output//\'/'}
|
||||
local CONTROL_CHAR=$'\033'
|
||||
output="${output//$CONTROL_CHAR/}"
|
||||
printf "%s" "$output"
|
||||
}
|
||||
|
||||
suite_buffer() {
|
||||
local output
|
||||
output="$("$@"; printf "x")" # use x marker to avoid losing trailing newlines
|
||||
_suite_buffer="${_suite_buffer}${output%x}"
|
||||
}
|
||||
|
||||
suite_flush() {
|
||||
echo -n "${_suite_buffer}"
|
||||
_suite_buffer=""
|
||||
}
|
||||
|
||||
buffer() {
|
||||
local output
|
||||
output="$("$@"; printf "x")" # use x marker to avoid losing trailing newlines
|
||||
_buffer="${_buffer}${output%x}"
|
||||
}
|
||||
|
||||
flush() {
|
||||
echo -n "${_buffer}"
|
||||
_buffer=""
|
||||
}
|
||||
|
||||
log() {
|
||||
if [[ -n "$_buffer_log" ]]; then
|
||||
_buffer_log="${_buffer_log}
|
||||
$1"
|
||||
else
|
||||
_buffer_log="$1"
|
||||
fi
|
||||
}
|
||||
|
||||
flush_log() {
|
||||
if [[ -n "$test_result_state" ]]; then
|
||||
buffer print_test_case
|
||||
fi
|
||||
_buffer_log=""
|
||||
_system_out_log=""
|
||||
}
|
||||
|
||||
log_system_out() {
|
||||
if [[ -n "$_system_out_log" ]]; then
|
||||
_system_out_log="${_system_out_log}
|
||||
$1"
|
||||
else
|
||||
_system_out_log="$1"
|
||||
fi
|
||||
}
|
||||
|
||||
finish_file() {
|
||||
if [[ "${class-JUNIT_FORMATTER_NO_FILE_ENCOUNTERED}" != JUNIT_FORMATTER_NO_FILE_ENCOUNTERED ]]; then
|
||||
file_header
|
||||
printf "%s\n" "${_buffer}"
|
||||
file_footer
|
||||
fi
|
||||
}
|
||||
|
||||
finish_suite() {
|
||||
flush_log
|
||||
suite_header
|
||||
suite_flush
|
||||
finish_file # must come after suite flush to not print the last file before the others
|
||||
suite_footer
|
||||
}
|
||||
|
||||
bats_tap_stream_plan() { # <number of tests>
|
||||
:
|
||||
}
|
||||
|
||||
init_suite
|
||||
trap finish_suite EXIT
|
||||
trap '' INT
|
||||
|
||||
bats_tap_stream_begin() { # <test index> <test name>
|
||||
flush_log
|
||||
# set after flushing to avoid overriding name of test
|
||||
name="$2"
|
||||
}
|
||||
|
||||
bats_tap_stream_ok() { # [--duration <milliseconds] <test index> <test name>
|
||||
if [[ "$1" == "--duration" ]]; then
|
||||
test_exec_time="${BASH_REMATCH[1]}"
|
||||
else
|
||||
test_exec_time=0
|
||||
fi
|
||||
((file_count += 1))
|
||||
test_result_state='ok'
|
||||
file_exec_time="$((file_exec_time + test_exec_time))"
|
||||
suite_test_exec_time=$((suite_test_exec_time + test_exec_time))
|
||||
}
|
||||
|
||||
bats_tap_stream_skipped() { # <test index> <test name> <skip reason>
|
||||
((file_count += 1))
|
||||
((file_skipped += 1))
|
||||
test_result_state='skipped'
|
||||
test_exec_time=0
|
||||
test_skip_message="$3"
|
||||
}
|
||||
|
||||
bats_tap_stream_not_ok() { # [--duration <milliseconds>] <test index> <test name>
|
||||
((file_count += 1))
|
||||
((file_failures += 1))
|
||||
if [[ "$1" == "--duration" ]]; then
|
||||
test_exec_time="${BASH_REMATCH[1]}"
|
||||
else
|
||||
test_exec_time=0
|
||||
fi
|
||||
test_result_state=not_ok
|
||||
file_exec_time="$((file_exec_time + test_exec_time))"
|
||||
suite_test_exec_time=$((suite_test_exec_time + test_exec_time))
|
||||
}
|
||||
|
||||
bats_tap_stream_comment() { # <comment text without leading '# '> <scope>
|
||||
local comment="$1" scope="$2"
|
||||
case "$scope" in
|
||||
begin)
|
||||
# everything that happens between begin and [not] ok is FD3 output from the test
|
||||
log_system_out "$comment"
|
||||
;;
|
||||
ok)
|
||||
# non failed tests can produce FD3 output
|
||||
log_system_out "$comment"
|
||||
;;
|
||||
*)
|
||||
# everything else is considered error output
|
||||
log "$1"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
bats_tap_stream_suite() { # <file name>
|
||||
flush_log
|
||||
suite_buffer finish_file
|
||||
init_file
|
||||
class="${1/$BASE_PATH}"
|
||||
}
|
||||
|
||||
bats_tap_stream_unknown() { # <full line>
|
||||
:
|
||||
}
|
||||
|
||||
bats_parse_internal_extended_tap
|
328
extras/portable/test/bats/libexec/bats-core/bats-format-pretty
Executable file
328
extras/portable/test/bats/libexec/bats-core/bats-format-pretty
Executable file
@ -0,0 +1,328 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# shellcheck source=lib/bats-core/formatter.bash
|
||||
source "$BATS_ROOT/lib/bats-core/formatter.bash"
|
||||
|
||||
BASE_PATH=.
|
||||
BATS_ENABLE_TIMING=
|
||||
|
||||
while [[ "$#" -ne 0 ]]; do
|
||||
case "$1" in
|
||||
-T)
|
||||
BATS_ENABLE_TIMING="-T"
|
||||
;;
|
||||
--base-path)
|
||||
shift
|
||||
normalize_base_path BASE_PATH "$1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
update_count_column_width() {
|
||||
count_column_width=$((${#count} * 2 + 2))
|
||||
if [[ -n "$BATS_ENABLE_TIMING" ]]; then
|
||||
# additional space for ' in %s sec'
|
||||
count_column_width=$((count_column_width + ${#SECONDS} + 8))
|
||||
fi
|
||||
# also update dependent value
|
||||
update_count_column_left
|
||||
}
|
||||
|
||||
update_screen_width() {
|
||||
screen_width="$(tput cols)"
|
||||
# also update dependent value
|
||||
update_count_column_left
|
||||
}
|
||||
|
||||
update_count_column_left() {
|
||||
count_column_left=$((screen_width - count_column_width))
|
||||
}
|
||||
|
||||
# avoid unset variables
|
||||
count=0
|
||||
screen_width=80
|
||||
update_count_column_width
|
||||
update_screen_width
|
||||
test_result=
|
||||
|
||||
trap update_screen_width WINCH
|
||||
|
||||
begin() {
|
||||
test_result= # reset to avoid carrying over result state from previous test
|
||||
line_backoff_count=0
|
||||
go_to_column 0
|
||||
update_count_column_width
|
||||
buffer_with_truncation $((count_column_left - 1)) ' %s' "$name"
|
||||
clear_to_end_of_line
|
||||
go_to_column $count_column_left
|
||||
if [[ -n "$BATS_ENABLE_TIMING" ]]; then
|
||||
buffer "%${#count}s/${count} in %s sec" "$index" "$SECONDS"
|
||||
else
|
||||
buffer "%${#count}s/${count}" "$index"
|
||||
fi
|
||||
go_to_column 1
|
||||
}
|
||||
|
||||
finish_test() {
|
||||
move_up $line_backoff_count
|
||||
go_to_column 0
|
||||
buffer "$@"
|
||||
if [[ -n "$BATS_ENABLE_TIMING" ]]; then
|
||||
set_color 2
|
||||
buffer ' [%s]' "$TIMING"
|
||||
fi
|
||||
advance
|
||||
move_down $(( line_backoff_count - 1 ))
|
||||
}
|
||||
|
||||
pass() {
|
||||
TIMING="${1:-}"
|
||||
finish_test ' ✓ %s' "$name"
|
||||
test_result=pass
|
||||
}
|
||||
|
||||
skip() {
|
||||
local reason="$1"
|
||||
if [[ -n "$reason" ]]; then
|
||||
reason=": $reason"
|
||||
fi
|
||||
BATS_ENABLE_TIMING='' finish_test ' - %s (skipped%s)' "$name" "$reason"
|
||||
test_result=skip
|
||||
}
|
||||
|
||||
fail() {
|
||||
set_color 1 bold
|
||||
TIMING="${1:-}"
|
||||
finish_test ' ✗ %s' "$name"
|
||||
test_result=fail
|
||||
}
|
||||
|
||||
log() {
|
||||
case ${test_result} in
|
||||
pass)
|
||||
clear_color
|
||||
;;
|
||||
fail)
|
||||
set_color 1
|
||||
;;
|
||||
esac
|
||||
buffer ' %s\n' "$1"
|
||||
clear_color
|
||||
}
|
||||
|
||||
summary() {
|
||||
if [ "$failures" -eq 0 ] ; then
|
||||
set_color 2 bold
|
||||
else
|
||||
set_color 1 bold
|
||||
fi
|
||||
|
||||
buffer '\n%d test' "$count"
|
||||
if [[ "$count" -ne 1 ]]; then
|
||||
buffer 's'
|
||||
fi
|
||||
|
||||
buffer ', %d failure' "$failures"
|
||||
if [[ "$failures" -ne 1 ]]; then
|
||||
buffer 's'
|
||||
fi
|
||||
|
||||
if [[ "$skipped" -gt 0 ]]; then
|
||||
buffer ', %d skipped' "$skipped"
|
||||
fi
|
||||
|
||||
not_run=$((count - passed - failures - skipped))
|
||||
if [[ "$not_run" -gt 0 ]]; then
|
||||
buffer ', %d not run' "$not_run"
|
||||
fi
|
||||
|
||||
if [[ -n "$BATS_ENABLE_TIMING" ]]; then
|
||||
buffer " in $SECONDS seconds"
|
||||
fi
|
||||
|
||||
buffer '\n'
|
||||
clear_color
|
||||
}
|
||||
|
||||
buffer_with_truncation() {
|
||||
local width="$1"
|
||||
shift
|
||||
local string
|
||||
|
||||
# shellcheck disable=SC2059
|
||||
printf -v 'string' -- "$@"
|
||||
|
||||
if [[ "${#string}" -gt "$width" ]]; then
|
||||
buffer '%s...' "${string:0:$((width - 4))}"
|
||||
else
|
||||
buffer '%s' "$string"
|
||||
fi
|
||||
}
|
||||
|
||||
move_up() {
|
||||
if [[ $1 -gt 0 ]]; then # avoid moving if we got 0
|
||||
buffer '\x1B[%dA' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
move_down() {
|
||||
if [[ $1 -gt 0 ]]; then # avoid moving if we got 0
|
||||
buffer '\x1B[%dB' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
go_to_column() {
|
||||
local column="$1"
|
||||
buffer '\x1B[%dG' $((column + 1))
|
||||
}
|
||||
|
||||
clear_to_end_of_line() {
|
||||
buffer '\x1B[K'
|
||||
}
|
||||
|
||||
advance() {
|
||||
clear_to_end_of_line
|
||||
buffer '\n'
|
||||
clear_color
|
||||
}
|
||||
|
||||
set_color() {
|
||||
local color="$1"
|
||||
local weight=22
|
||||
|
||||
if [[ "${2:-}" == 'bold' ]]; then
|
||||
weight=1
|
||||
fi
|
||||
buffer '\x1B[%d;%dm' "$((30 + color))" "$weight"
|
||||
}
|
||||
|
||||
clear_color() {
|
||||
buffer '\x1B[0m'
|
||||
}
|
||||
|
||||
_buffer=
|
||||
|
||||
buffer() {
|
||||
local content
|
||||
# shellcheck disable=SC2059
|
||||
printf -v content -- "$@"
|
||||
_buffer+="$content"
|
||||
}
|
||||
|
||||
prefix_buffer_with() {
|
||||
local old_buffer="$_buffer"
|
||||
_buffer=''
|
||||
"$@"
|
||||
_buffer="$_buffer$old_buffer"
|
||||
}
|
||||
|
||||
flush() {
|
||||
printf '%s' "$_buffer"
|
||||
_buffer=
|
||||
}
|
||||
|
||||
finish() {
|
||||
flush
|
||||
printf '\n'
|
||||
}
|
||||
|
||||
trap finish EXIT
|
||||
trap '' INT
|
||||
|
||||
bats_tap_stream_plan() {
|
||||
count="$1"
|
||||
index=0
|
||||
passed=0
|
||||
failures=0
|
||||
skipped=0
|
||||
name=
|
||||
update_count_column_width
|
||||
}
|
||||
|
||||
bats_tap_stream_begin() {
|
||||
index="$1"
|
||||
name="$2"
|
||||
begin
|
||||
flush
|
||||
}
|
||||
|
||||
bats_tap_stream_ok() {
|
||||
local duration=
|
||||
if [[ "$1" == "--duration" ]]; then
|
||||
duration="$2"
|
||||
shift 2
|
||||
fi
|
||||
index="$1"
|
||||
name="$2"
|
||||
((++passed))
|
||||
|
||||
pass "$duration"
|
||||
}
|
||||
|
||||
bats_tap_stream_skipped() {
|
||||
index="$1"
|
||||
name="$2"
|
||||
((++skipped))
|
||||
skip "$3"
|
||||
}
|
||||
|
||||
bats_tap_stream_not_ok() {
|
||||
local duration=
|
||||
if [[ "$1" == "--duration" ]]; then
|
||||
duration="$2"
|
||||
shift 2
|
||||
fi
|
||||
index="$1"
|
||||
name="$2"
|
||||
((++failures))
|
||||
|
||||
fail "$duration"
|
||||
}
|
||||
|
||||
bats_tap_stream_comment() { # <comment> <scope>
|
||||
local scope=$2
|
||||
# count the lines we printed after the begin text,
|
||||
if [[ $line_backoff_count -eq 0 && $scope == begin ]]; then
|
||||
# if this is the first line after begin, go down one line
|
||||
buffer "\n"
|
||||
(( ++line_backoff_count )) # prefix-increment to avoid "error" due to returning 0
|
||||
fi
|
||||
|
||||
(( ++line_backoff_count ))
|
||||
(( line_backoff_count += ${#1} / screen_width)) # account for linebreaks due to length
|
||||
log "$1"
|
||||
}
|
||||
|
||||
bats_tap_stream_suite() {
|
||||
#test_file="$1"
|
||||
line_backoff_count=0
|
||||
index=
|
||||
# indicate filename for failures
|
||||
local file_name="${1/$BASE_PATH}"
|
||||
name="File $file_name"
|
||||
set_color 4 bold
|
||||
buffer "%s\n" "$file_name"
|
||||
clear_color
|
||||
}
|
||||
|
||||
line_backoff_count=0
|
||||
bats_tap_stream_unknown() { # <full line> <scope>
|
||||
local scope=$2
|
||||
# count the lines we printed after the begin text, (or after suite, in case of syntax errors)
|
||||
if [[ $line_backoff_count -eq 0 && ( $scope == begin || $scope == suite )]]; then
|
||||
# if this is the first line after begin, go down one line
|
||||
buffer "\n"
|
||||
(( ++line_backoff_count )) # prefix-increment to avoid "error" due to returning 0
|
||||
fi
|
||||
|
||||
(( ++line_backoff_count ))
|
||||
(( line_backoff_count += ${#1} / screen_width)) # account for linebreaks due to length
|
||||
buffer "%s\n" "$1"
|
||||
flush
|
||||
}
|
||||
|
||||
bats_parse_internal_extended_tap
|
||||
|
||||
summary
|
52
extras/portable/test/bats/libexec/bats-core/bats-format-tap
Executable file
52
extras/portable/test/bats/libexec/bats-core/bats-format-tap
Executable file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
trap '' INT
|
||||
|
||||
# shellcheck source=lib/bats-core/formatter.bash
|
||||
source "$BATS_ROOT/lib/bats-core/formatter.bash"
|
||||
|
||||
bats_tap_stream_plan() {
|
||||
printf "1..%d\n" "$1"
|
||||
}
|
||||
|
||||
bats_tap_stream_begin() { #<test index> <test name>
|
||||
:
|
||||
}
|
||||
|
||||
bats_tap_stream_ok() { # [--duration <milliseconds] <test index> <test name>
|
||||
if [[ "$1" == "--duration" ]]; then
|
||||
printf "ok %d %s # in %d ms\n" "$3" "$4" "$2"
|
||||
else
|
||||
printf "ok %d %s\n" "$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
bats_tap_stream_not_ok() { # [--duration <milliseconds>] <test index> <test name>
|
||||
if [[ "$1" == "--duration" ]]; then
|
||||
printf "not ok %d %s # in %d ms\n" "$3" "$4" "$2"
|
||||
else
|
||||
printf "not ok %d %s\n" "$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
bats_tap_stream_skipped() { # <test index> <test name> <reason>
|
||||
if [[ -n "$3" ]]; then
|
||||
printf "ok %d %s # skip %s\n" "$1" "$2" "$3"
|
||||
else
|
||||
printf "ok %d %s # skip\n" "$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
bats_tap_stream_comment() { # <comment text without leading '# '>
|
||||
printf "# %s\n" "$1"
|
||||
}
|
||||
|
||||
bats_tap_stream_suite() { # <file name>
|
||||
:
|
||||
}
|
||||
|
||||
bats_tap_stream_unknown() { # <full line>
|
||||
printf "%s\n" "$1"
|
||||
}
|
||||
|
||||
bats_parse_internal_extended_tap
|
91
extras/portable/test/bats/libexec/bats-core/bats-format-tap13
Executable file
91
extras/portable/test/bats/libexec/bats-core/bats-format-tap13
Executable file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
while [[ "$#" -ne 0 ]]; do
|
||||
case "$1" in
|
||||
-T)
|
||||
BATS_ENABLE_TIMING="-T"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
header_pattern='[0-9]+\.\.[0-9]+'
|
||||
IFS= read -r header
|
||||
|
||||
if [[ "$header" =~ $header_pattern ]]; then
|
||||
printf "TAP version 13\n"
|
||||
printf "%s\n" "$header"
|
||||
else
|
||||
# If the first line isn't a TAP plan, print it and pass the rest through
|
||||
printf '%s\n' "$header"
|
||||
exec cat
|
||||
fi
|
||||
|
||||
yaml_block_open=''
|
||||
add_yaml_entry() {
|
||||
if [[ -z "$yaml_block_open" ]]; then
|
||||
printf " ---\n"
|
||||
fi
|
||||
printf " %s: %s\n" "$1" "$2"
|
||||
yaml_block_open=1
|
||||
}
|
||||
|
||||
close_previous_yaml_block() {
|
||||
if [[ -n "$yaml_block_open" ]]; then
|
||||
printf " ...\n"
|
||||
yaml_block_open=''
|
||||
fi
|
||||
}
|
||||
|
||||
trap '' INT
|
||||
|
||||
number_of_printed_log_lines_for_this_test_so_far=0
|
||||
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
'begin '*) ;;
|
||||
'ok '*)
|
||||
close_previous_yaml_block
|
||||
number_of_printed_log_lines_for_this_test_so_far=0
|
||||
if [[ -n "${BATS_ENABLE_TIMING-}" ]]; then
|
||||
timing_expr="(ok [0-9]+ .+) in ([0-9]+)ms$"
|
||||
if [[ "$line" =~ $timing_expr ]]; then
|
||||
printf "%s\n" "${BASH_REMATCH[1]}"
|
||||
add_yaml_entry "duration_ms" "${BASH_REMATCH[2]}"
|
||||
else
|
||||
echo "Could not match output line to timing regex: $line" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
printf "%s\n" "${line}"
|
||||
fi
|
||||
;;
|
||||
'not ok '*)
|
||||
close_previous_yaml_block
|
||||
number_of_printed_log_lines_for_this_test_so_far=0
|
||||
timing_expr="(not ok [0-9]+ .+) in ([0-9])+ms$"
|
||||
if [[ -n "${BATS_ENABLE_TIMING-}" ]]; then
|
||||
if [[ "$line" =~ $timing_expr ]]; then
|
||||
printf "%s\n" "${BASH_REMATCH[1]}"
|
||||
add_yaml_entry "duration_ms" "${BASH_REMATCH[2]}"
|
||||
else
|
||||
echo "Could not match failure line to timing regex: $line" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
printf "%s\n" "${line}"
|
||||
fi
|
||||
;;
|
||||
'# '*)
|
||||
if [[ $number_of_printed_log_lines_for_this_test_so_far -eq 0 ]]; then
|
||||
add_yaml_entry "message" "|" # use a multiline string for this entry
|
||||
fi
|
||||
((++number_of_printed_log_lines_for_this_test_so_far))
|
||||
printf " %s\n" "${line:2}"
|
||||
;;
|
||||
'suite '*) ;;
|
||||
esac
|
||||
done
|
||||
# close the final block if there was one
|
||||
close_previous_yaml_block
|
60
extras/portable/test/bats/libexec/bats-core/bats-preprocess
Executable file
60
extras/portable/test/bats/libexec/bats-core/bats-preprocess
Executable file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
bats_encode_test_name() {
|
||||
local name="$1"
|
||||
local result='test_'
|
||||
local hex_code
|
||||
|
||||
if [[ ! "$name" =~ [^[:alnum:]\ _-] ]]; then
|
||||
name="${name//_/-5f}"
|
||||
name="${name//-/-2d}"
|
||||
name="${name// /_}"
|
||||
result+="$name"
|
||||
else
|
||||
local length="${#name}"
|
||||
local char i
|
||||
|
||||
for ((i = 0; i < length; i++)); do
|
||||
char="${name:$i:1}"
|
||||
if [[ "$char" == ' ' ]]; then
|
||||
result+='_'
|
||||
elif [[ "$char" =~ [[:alnum:]] ]]; then
|
||||
result+="$char"
|
||||
else
|
||||
printf -v 'hex_code' -- '-%02x' \'"$char"
|
||||
result+="$hex_code"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
printf -v "$2" '%s' "$result"
|
||||
}
|
||||
|
||||
BATS_TEST_PATTERN="^[[:blank:]]*@test[[:blank:]]+(.*[^[:blank:]])[[:blank:]]+\{(.*)\$"
|
||||
BATS_TEST_PATTERN_COMMENT="[[:blank:]]*([^[:blank:]()]+)[[:blank:]]*\(?\)?[[:blank:]]+\{[[:blank:]]+#[[:blank:]]*@test[[:blank:]]*\$"
|
||||
|
||||
test_file="$1"
|
||||
tests=()
|
||||
{
|
||||
while IFS= read -r line; do
|
||||
line="${line//$'\r'/}"
|
||||
if [[ "$line" =~ $BATS_TEST_PATTERN ]] || [[ "$line" =~ $BATS_TEST_PATTERN_COMMENT ]]; then
|
||||
name="${BASH_REMATCH[1]#[\'\"]}"
|
||||
name="${name%[\'\"]}"
|
||||
body="${BASH_REMATCH[2]:-}"
|
||||
bats_encode_test_name "$name" 'encoded_name'
|
||||
printf '%s() { bats_test_begin "%s"; %s\n' "${encoded_name:?}" "$name" "$body" || :
|
||||
|
||||
if [[ -z "$BATS_TEST_FILTER" || "$name" =~ $BATS_TEST_FILTER ]]; then
|
||||
tests+=("$encoded_name")
|
||||
fi
|
||||
else
|
||||
printf '%s\n' "$line"
|
||||
fi
|
||||
done
|
||||
} <<<"$(<"$test_file")"$'\n'
|
||||
|
||||
for test_name in "${tests[@]}"; do
|
||||
printf 'bats_test_function %s\n' "$test_name"
|
||||
done
|
197
extras/portable/test/bats_setup
Normal file
197
extras/portable/test/bats_setup
Normal file
@ -0,0 +1,197 @@
|
||||
# setup paths for BATS test units
|
||||
setup() {
|
||||
[ ! -f ${BATS_PARENT_TMPNAME}.skip ] || skip "skip remaining tests"
|
||||
bats_require_minimum_version 1.5.0
|
||||
R="$BATS_TEST_DIRNAME"
|
||||
# R=`cd "$T"/.. && pwd`
|
||||
TMP="$BATS_FILE_TMPDIR"
|
||||
load test_helper/bats-support/load
|
||||
load test_helper/bats-assert/load
|
||||
load test_helper/bats-file/load
|
||||
ZTMP="$BATS_FILE_TMPDIR"
|
||||
if [ "$ZENROOM_EXECUTABLE" == "" ]; then
|
||||
ZENROOM_EXECUTABLE="/usr/local/bin/zenroom"
|
||||
fi
|
||||
|
||||
PATH="$PATH:/usr/local/bin:/usr/local/sbin"
|
||||
MNT="/media/`basename $BATS_TEST_FILENAME`"
|
||||
PIM=42
|
||||
# max password stdin size to veracrypt is 128 bytes
|
||||
PW="91cd69b2caab05cb64f8e1c8ae22a7c5a25564e7fc5116d0303dce1ffd26861ea0483c25bdb85adb216718c19815eb59ac14ec9783bfbbb57786ca7d9038c845"
|
||||
# `openssl rand -hex 64`"
|
||||
FS='ext4'
|
||||
SIZE='20M'
|
||||
[ "$TOMB" = "" ] && TOMB=test.tomb
|
||||
|
||||
# default on freebsd is 1001
|
||||
user_uid=1000
|
||||
user_gid=1000
|
||||
|
||||
system="`uname -s`"
|
||||
f_create=""
|
||||
f_format=""
|
||||
f_map=""
|
||||
f_mount=""
|
||||
f_close=""
|
||||
|
||||
case "$system" in
|
||||
FreeBSD)
|
||||
f_create=portable_create
|
||||
f_format=freebsd_format
|
||||
f_map=portable_map
|
||||
f_mount=freebsd_mount
|
||||
f_close=freebsd_close
|
||||
user_uid=1001
|
||||
user_gid=1001
|
||||
;;
|
||||
Linux)
|
||||
f_create=portable_create
|
||||
f_format=linux_format
|
||||
f_map=portable_map
|
||||
f_mount=linux_mount
|
||||
f_close=portable_close
|
||||
user_uid=1000
|
||||
user_gid=1000
|
||||
;;
|
||||
*)
|
||||
>&2 echo "Unsupported system: $system"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# cd $ZTMP
|
||||
}
|
||||
|
||||
teardown() {
|
||||
[ -n "$BATS_TEST_COMPLETED" ] || touch ${BATS_PARENT_TMPNAME}.skip
|
||||
>&3 echo
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
# usage: echo PASSWORD | portable_create file size pim
|
||||
portable_create() {
|
||||
local file="$1" # must not exist
|
||||
local size="$2" # veracrypt format (accepts M or G)
|
||||
local pim="$3" # any number
|
||||
# >&2 echo "portable_create $file $size $pim"
|
||||
veracrypt --non-interactive --text --stdin \
|
||||
-m nokernelcrypto \
|
||||
-c ${file} --volume-type normal \
|
||||
--hash sha512 --encryption serpent-aes \
|
||||
--filesystem none --size ${size} --pim ${pim} \
|
||||
--random-source /dev/urandom -k ''
|
||||
return $?
|
||||
}
|
||||
|
||||
# usage: echo PASSWORD | portable_map file pim
|
||||
portable_map() {
|
||||
local file="$1"
|
||||
local pim="$2"
|
||||
# >&2 echo "portable_map $file $pim"
|
||||
veracrypt --non-interactive --text --stdin \
|
||||
--protect-hidden no -m nokernelcrypto \
|
||||
-k '' --pim ${pim} --filesystem none \
|
||||
${file}
|
||||
local loop=`veracrypt -l "$file" | awk '{print $3}'`
|
||||
return $?
|
||||
}
|
||||
|
||||
portable_close() {
|
||||
local file="$1"
|
||||
veracrypt -d ${file}
|
||||
return $?
|
||||
}
|
||||
|
||||
linux_format() {
|
||||
local file="$1"
|
||||
# loop="`losetup -j ${vera}/volume | cut -d: -f1`"
|
||||
local loop=`veracrypt -l "$FILE" | awk '{print $3}'`
|
||||
# losetup -l
|
||||
>&2 echo "veramap format: ${loop}"
|
||||
sync
|
||||
sudo mkfs.ext4 -E root_owner="${user_uid}:${user_gid}" "$loop"
|
||||
return $?
|
||||
}
|
||||
|
||||
# usage: _mount /tmp/.veracrypt_ mountpoint
|
||||
linux_mount() {
|
||||
local file="$1"
|
||||
local mnt="$2"
|
||||
# local loop="`losetup -j ${vera}/volume | cut -d: -f1`"
|
||||
local loop=`veracrypt -l "$file" | awk '{print $3}'`
|
||||
>&3 echo "fsck $loop"
|
||||
fsck.ext4 -p -C0 "$loop"
|
||||
sudo mount ${loop} "$mnt"
|
||||
return $?
|
||||
}
|
||||
|
||||
freebsd_format() {
|
||||
file="$1"
|
||||
local loop=`veracrypt -l "$FILE" | awk '{print $3}'`
|
||||
mkfs.ext4 -E root_owner="${user_uid}:${user_gid}" "${loop}"
|
||||
return $?
|
||||
}
|
||||
|
||||
freebsd_mount() {
|
||||
local file="$1"
|
||||
local mnt="$2"
|
||||
>&2 echo `veracrypt -l "$file"`
|
||||
local loop=`veracrypt -l "$file" | awk '{print $3}'`
|
||||
>&3 echo "fsck $loop"
|
||||
fsck.ext4 -p -C0 "$loop"
|
||||
lklfuse -o type=ext4 "${loop}" "$mnt"
|
||||
return $?
|
||||
}
|
||||
|
||||
freebsd_close() {
|
||||
local file="$1"
|
||||
local md=`veracrypt -l "$file" | awk '{print $3}'`
|
||||
# umount "$mnt"
|
||||
>&2 echo "md: $md"
|
||||
local mnt=`pgrep -lf "lklfuse.*$md" | awk '{print $6}'`
|
||||
>&2 echo "mnt: $mnt"
|
||||
lkl=`pgrep -f "lklfuse.*$md" | awk '{print $1}'`
|
||||
>&3 echo "kill $lkl (lklfuse on $md)"
|
||||
# trying to deail with lklfuse bug
|
||||
# https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=239831
|
||||
renice -20 $lkl
|
||||
kill $lkl
|
||||
sync
|
||||
sleep 1
|
||||
kill -9 $lkl
|
||||
# lkl should have really exited now
|
||||
>&3 echo "veracrypt -d $file"
|
||||
veracrypt -d "$file"
|
||||
return $?
|
||||
}
|
||||
|
||||
Z() {
|
||||
tmptmp=0
|
||||
if ! [ "$TMP" ]; then
|
||||
TMP=`mktemp -d`; tmptmp=1
|
||||
fi
|
||||
script=$1
|
||||
if [ "$script" == "-" ]; then
|
||||
cat > $TMP/script_stdin
|
||||
script=$TMP/script_stdin
|
||||
else
|
||||
if ! [ -r "$script" ]; then
|
||||
script=$T/$script
|
||||
fi
|
||||
fi
|
||||
if ! [ -r $script ]; then
|
||||
>&2 echo "Error - script not found: $script"
|
||||
return 1
|
||||
fi
|
||||
shift 1
|
||||
if [ "${1##*.}" == "zen" ]; then
|
||||
$ZENROOM_EXECUTABLE $@ -z $script
|
||||
else
|
||||
$ZENROOM_EXECUTABLE $@ $script
|
||||
fi
|
||||
if [ $tmptmp = 1 ]; then
|
||||
rm -f $TMP/*
|
||||
rmdir $TMP
|
||||
fi
|
||||
}
|
26
extras/portable/test/check-random-data.bats
Normal file
26
extras/portable/test/check-random-data.bats
Normal file
@ -0,0 +1,26 @@
|
||||
load bats_setup
|
||||
|
||||
@test "Find the tomb" {
|
||||
assert_file_exists "$TOMB"
|
||||
>&3 echo "Found: $TOMB"
|
||||
}
|
||||
|
||||
@test "Open tomb with key" {
|
||||
mkdir -p "$TOMB".mnt
|
||||
./tomb open -k "$TOMB".key "$TOMB" "$TOMB".mnt
|
||||
}
|
||||
|
||||
@test "Check integrity of random data" {
|
||||
sha512sum "$TOMB".mnt/random.data | awk '{print $1}'
|
||||
cat "$TOMB".hash
|
||||
>&2 echo $newhash
|
||||
>&2 echo $oldhash
|
||||
assert_equal "$newhash" "$oldhash"
|
||||
if [ -r "$TOMB".uname ]; then
|
||||
>&3 cat "$TOMB".uname
|
||||
fi
|
||||
}
|
||||
|
||||
@test "Close tomb" {
|
||||
./tomb close "$TOMB"
|
||||
}
|
79
extras/portable/test/create-fillrandom.bats
Normal file
79
extras/portable/test/create-fillrandom.bats
Normal file
@ -0,0 +1,79 @@
|
||||
load bats_setup
|
||||
|
||||
# f_create=""
|
||||
# f_format=""
|
||||
# f_map=""
|
||||
# f_mount=""
|
||||
# f_close=""
|
||||
|
||||
@test "Create a new tomb" {
|
||||
# >&3 echo $PW
|
||||
>&3 echo $TOMB
|
||||
echo -n "$PW" | $f_create "$TOMB" 20M ${PIM}
|
||||
}
|
||||
|
||||
@test "Map the tomb" {
|
||||
echo -n "$PW" | $f_map "$TOMB" ${PIM}
|
||||
}
|
||||
|
||||
@test "Format the tomb" {
|
||||
$f_format "/tmp/.veracrypt_aux_mnt1" || {
|
||||
$f_close "$TOMB"
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@test "Mount the tomb" {
|
||||
mkdir -p "$MNT"
|
||||
$f_mount "$TOMB" "$MNT" || {
|
||||
$f_close "$TOMB"
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@test "Create random.data inside the tomb" {
|
||||
dd if=/dev/urandom of="$MNT"/random.data bs=1024 count=10000 || {
|
||||
# sudo umount testmnt
|
||||
$f_close "$TOMB"
|
||||
return false
|
||||
}
|
||||
>&3 ls -l "$MNT"/random.data
|
||||
sha512sum "$MNT"/random.data | awk '{print $1}' | >&3 tee "$TOMB".hash
|
||||
uname -a > "$TOMB".uname
|
||||
}
|
||||
|
||||
@test "Close the test.tomb" {
|
||||
>&3 veracrypt -l
|
||||
# sudo umount "$TMP"/testmnt
|
||||
$f_close "$TOMB"
|
||||
}
|
||||
|
||||
|
||||
@test "Re-Map the test.tomb" {
|
||||
echo -n "$PW" | $f_map "$TOMB" ${PIM}
|
||||
}
|
||||
|
||||
@test "Re-Mount the test.tomb" {
|
||||
mkdir -p "$MNT"
|
||||
$f_mount "$TOMB" "$MNT" || {
|
||||
$f_close "$TOMB"
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@test "Re-Check integrity of random data" {
|
||||
newhash=`sha512sum "$MNT"/random.data | awk '{print $1}'`
|
||||
oldhash=`cat "$TOMB".hash`
|
||||
>&2 echo $newhash
|
||||
>&2 echo $oldhash
|
||||
assert_equal "$newhash" "$oldhash"
|
||||
if [ -r "$TOMB".uname ]; then
|
||||
>&3 cat "$TOMB".uname
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@test "Re-Close the test.tomb" {
|
||||
>&3 veracrypt -l
|
||||
$f_close "$TOMB"
|
||||
}
|
51
extras/portable/test/create_open_close.bats
Normal file
51
extras/portable/test/create_open_close.bats
Normal file
@ -0,0 +1,51 @@
|
||||
load bats_setup
|
||||
|
||||
@test "Dig tomb" {
|
||||
rm -f "$TOMB"
|
||||
>&3 echo "$TOMB"
|
||||
./tomb dig -s 20 "$TOMB"
|
||||
}
|
||||
|
||||
@test "Forge key" {
|
||||
rm -f "$TOMB".key
|
||||
./tomb forge "$TOMB".key
|
||||
}
|
||||
|
||||
@test "Lock tomb with key" {
|
||||
./tomb lock -k "$TOMB".key "$TOMB"
|
||||
}
|
||||
|
||||
@test "Open tomb with key" {
|
||||
mkdir -p "$TOMB".mnt
|
||||
./tomb open -k "$TOMB".key "$TOMB" "$TOMB".mnt
|
||||
}
|
||||
|
||||
@test "Create random.data inside the tomb" {
|
||||
dd if=/dev/urandom of="$TOMB".mnt/random.data bs=1024 count=10000
|
||||
>&3 ls -l "$TOMB".mnt/random.data
|
||||
sha512sum "$TOMB".mnt/random.data | awk '{print $1}' | >&3 tee "$TOMB".hash
|
||||
uname -a > "$TOMB".uname
|
||||
}
|
||||
|
||||
@test "Close tomb" {
|
||||
./tomb close "$TOMB"
|
||||
}
|
||||
|
||||
@test "Re-open tomb with key" {
|
||||
./tomb open -k "$TOMB".key "$TOMB" "$TOMB".mnt
|
||||
}
|
||||
|
||||
@test "Check integrity of random data" {
|
||||
newhash=`sha512sum "$TOMB".mnt/random.data | awk '{print $1}'`
|
||||
oldhash=`cat "$TOMB".hash`
|
||||
>&2 echo $newhash
|
||||
>&2 echo $oldhash
|
||||
assert_equal "$newhash" "$oldhash"
|
||||
if [ -r "$TOMB".uname ]; then
|
||||
>&3 cat "$TOMB".uname
|
||||
fi
|
||||
}
|
||||
|
||||
@test "Close the tomb again" {
|
||||
./tomb close "$TOMB"
|
||||
}
|
33
extras/portable/test/test_helper/bats-assert/load.bash
Normal file
33
extras/portable/test/test_helper/bats-assert/load.bash
Normal file
@ -0,0 +1,33 @@
|
||||
# bats-assert - Common assertions for Bats
|
||||
#
|
||||
# Written in 2016 by Zoltan Tombol <zoltan dot tombol at gmail dot com>
|
||||
#
|
||||
# To the extent possible under law, the author(s) have dedicated all
|
||||
# copyright and related and neighboring rights to this software to the
|
||||
# public domain worldwide. This software is distributed without any
|
||||
# warranty.
|
||||
#
|
||||
# You should have received a copy of the CC0 Public Domain Dedication
|
||||
# along with this software. If not, see
|
||||
# <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
#
|
||||
# Assertions are functions that perform a test and output relevant
|
||||
# information on failure to help debugging. They return 1 on failure
|
||||
# and 0 otherwise.
|
||||
#
|
||||
# All output is formatted for readability using the functions of
|
||||
# `output.bash' and sent to the standard error.
|
||||
|
||||
# shellcheck disable=1090
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/assert.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/refute.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/assert_equal.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/assert_not_equal.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/assert_success.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/assert_failure.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/assert_output.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/refute_output.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/assert_line.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/refute_line.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/assert_regex.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/refute_regex.bash"
|
42
extras/portable/test/test_helper/bats-assert/src/assert.bash
Normal file
42
extras/portable/test/test_helper/bats-assert/src/assert.bash
Normal file
@ -0,0 +1,42 @@
|
||||
# assert
|
||||
# ======
|
||||
#
|
||||
# Summary: Fail if the given expression evaluates to false.
|
||||
#
|
||||
# Usage: assert <expression>
|
||||
|
||||
# Options:
|
||||
# <expression> The expression to evaluate for truthiness.
|
||||
# *__Note:__ The expression must be a simple command.
|
||||
# [Compound commands](https://www.gnu.org/software/bash/manual/bash.html#Compound-Commands),
|
||||
# such as `[[`, can be used only when executed with `bash -c`.*
|
||||
#
|
||||
# IO:
|
||||
# STDERR - the failed expression, on failure
|
||||
# Globals:
|
||||
# none
|
||||
# Returns:
|
||||
# 0 - if expression evaluates to true
|
||||
# 1 - otherwise
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert()' {
|
||||
# touch '/var/log/test.log'
|
||||
# assert [ -e '/var/log/test.log' ]
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the failed expression is displayed.
|
||||
#
|
||||
# ```
|
||||
# -- assertion failed --
|
||||
# expression : [ -e /var/log/test.log ]
|
||||
# --
|
||||
# ```
|
||||
assert() {
|
||||
if ! "$@"; then
|
||||
batslib_print_kv_single 10 'expression' "$*" \
|
||||
| batslib_decorate 'assertion failed' \
|
||||
| fail
|
||||
fi
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
# assert_equal
|
||||
# ============
|
||||
#
|
||||
# Summary: Fail if the actual and expected values are not equal.
|
||||
#
|
||||
# Usage: assert_equal <actual> <expected>
|
||||
#
|
||||
# Options:
|
||||
# <actual> The value being compared.
|
||||
# <expected> The value to compare against.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_equal()' {
|
||||
# assert_equal 'have' 'want'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# IO:
|
||||
# STDERR - expected and actual values, on failure
|
||||
# Globals:
|
||||
# none
|
||||
# Returns:
|
||||
# 0 - if values equal
|
||||
# 1 - otherwise
|
||||
#
|
||||
# On failure, the expected and actual values are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- values do not equal --
|
||||
# expected : want
|
||||
# actual : have
|
||||
# --
|
||||
# ```
|
||||
assert_equal() {
|
||||
if [[ $1 != "$2" ]]; then
|
||||
batslib_print_kv_single_or_multi 8 \
|
||||
'expected' "$2" \
|
||||
'actual' "$1" \
|
||||
| batslib_decorate 'values do not equal' \
|
||||
| fail
|
||||
fi
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
# assert_failure
|
||||
# ==============
|
||||
#
|
||||
# Summary: Fail if `$status` is 0; or is not equal to the optionally provided status.
|
||||
#
|
||||
# Usage: assert_failure [<expected_status>]
|
||||
#
|
||||
# Options:
|
||||
# <expected_status> The specific status code to check against.
|
||||
# If not provided, simply asserts status is != 0.
|
||||
#
|
||||
# IO:
|
||||
# STDERR - `$output`, on failure;
|
||||
# - also, `$status` and `expected_status`, if provided
|
||||
# Globals:
|
||||
# status
|
||||
# output
|
||||
# Returns:
|
||||
# 0 - if `$status' is 0,
|
||||
# or if expected_status is provided but does not equal `$status'
|
||||
# 1 - otherwise
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_failure() status only' {
|
||||
# run echo 'Success!'
|
||||
# assert_failure
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, `$output` is displayed.
|
||||
#
|
||||
# ```
|
||||
# -- command succeeded, but it was expected to fail --
|
||||
# output : Success!
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Expected status
|
||||
#
|
||||
# When `expected_status` is provided, fail if `$status` does not equal the `expected_status`.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_failure() with expected status' {
|
||||
# run bash -c "echo 'Error!'; exit 1"
|
||||
# assert_failure 2
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, both the expected and actual statuses, and `$output` are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- command failed as expected, but status differs --
|
||||
# expected : 2
|
||||
# actual : 1
|
||||
# output : Error!
|
||||
# --
|
||||
# ```
|
||||
assert_failure() {
|
||||
: "${output?}"
|
||||
: "${status?}"
|
||||
|
||||
(( $# > 0 )) && local -r expected="$1"
|
||||
if (( status == 0 )); then
|
||||
batslib_print_kv_single_or_multi 6 'output' "$output" \
|
||||
| batslib_decorate 'command succeeded, but it was expected to fail' \
|
||||
| fail
|
||||
elif (( $# > 0 )) && (( status != expected )); then
|
||||
{ local -ir width=8
|
||||
batslib_print_kv_single "$width" \
|
||||
'expected' "$expected" \
|
||||
'actual' "$status"
|
||||
batslib_print_kv_single_or_multi "$width" \
|
||||
'output' "$output"
|
||||
} \
|
||||
| batslib_decorate 'command failed as expected, but status differs' \
|
||||
| fail
|
||||
fi
|
||||
}
|
@ -0,0 +1,248 @@
|
||||
# assert_line
|
||||
# ===========
|
||||
#
|
||||
# Summary: Fail if the expected line is not found in the output (default) or at a specific line number.
|
||||
#
|
||||
# Usage: assert_line [-n index] [-p | -e] [--] <expected>
|
||||
#
|
||||
# Options:
|
||||
# -n, --index <idx> Match the <idx>th line
|
||||
# -p, --partial Match if `expected` is a substring of `$output` or line <idx>
|
||||
# -e, --regexp Treat `expected` as an extended regular expression
|
||||
# <expected> The expected line string, substring, or regular expression
|
||||
#
|
||||
# IO:
|
||||
# STDERR - details, on failure
|
||||
# error message, on error
|
||||
# Globals:
|
||||
# output
|
||||
# lines
|
||||
# Returns:
|
||||
# 0 - if matching line found
|
||||
# 1 - otherwise
|
||||
#
|
||||
# Similarly to `assert_output`, this function verifies that a command or function produces the expected output.
|
||||
# (It is the logical complement of `refute_line`.)
|
||||
# It checks that the expected line appears in the output (default) or at a specific line number.
|
||||
# Matching can be literal (default), partial or regular expression.
|
||||
#
|
||||
# *__Warning:__
|
||||
# Due to a [bug in Bats][bats-93], empty lines are discarded from `${lines[@]}`,
|
||||
# causing line indices to change and preventing testing for empty lines.*
|
||||
#
|
||||
# [bats-93]: https://github.com/sstephenson/bats/pull/93
|
||||
#
|
||||
# ## Looking for a line in the output
|
||||
#
|
||||
# By default, the entire output is searched for the expected line.
|
||||
# The assertion fails if the expected line is not found in `${lines[@]}`.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_line() looking for line' {
|
||||
# run echo $'have-0\nhave-1\nhave-2'
|
||||
# assert_line 'want'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the expected line and the output are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- output does not contain line --
|
||||
# line : want
|
||||
# output (3 lines):
|
||||
# have-0
|
||||
# have-1
|
||||
# have-2
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Matching a specific line
|
||||
#
|
||||
# When the `--index <idx>` option is used (`-n <idx>` for short), the expected line is matched only against the line identified by the given index.
|
||||
# The assertion fails if the expected line does not equal `${lines[<idx>]}`.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_line() specific line' {
|
||||
# run echo $'have-0\nhave-1\nhave-2'
|
||||
# assert_line --index 1 'want-1'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the index and the compared lines are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- line differs --
|
||||
# index : 1
|
||||
# expected : want-1
|
||||
# actual : have-1
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Partial matching
|
||||
#
|
||||
# Partial matching can be enabled with the `--partial` option (`-p` for short).
|
||||
# When used, a match fails if the expected *substring* is not found in the matched line.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_line() partial matching' {
|
||||
# run echo $'have 1\nhave 2\nhave 3'
|
||||
# assert_line --partial 'want'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the same details are displayed as for literal matching, except that the substring replaces the expected line.
|
||||
#
|
||||
# ```
|
||||
# -- no output line contains substring --
|
||||
# substring : want
|
||||
# output (3 lines):
|
||||
# have 1
|
||||
# have 2
|
||||
# have 3
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Regular expression matching
|
||||
#
|
||||
# Regular expression matching can be enabled with the `--regexp` option (`-e` for short).
|
||||
# When used, a match fails if the *extended regular expression* does not match the line being tested.
|
||||
#
|
||||
# *__Note__:
|
||||
# As expected, the anchors `^` and `$` bind to the beginning and the end (respectively) of the matched line.*
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_line() regular expression matching' {
|
||||
# run echo $'have-0\nhave-1\nhave-2'
|
||||
# assert_line --index 1 --regexp '^want-[0-9]$'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the same details are displayed as for literal matching, except that the regular expression replaces the expected line.
|
||||
#
|
||||
# ```
|
||||
# -- regular expression does not match line --
|
||||
# index : 1
|
||||
# regexp : ^want-[0-9]$
|
||||
# line : have-1
|
||||
# --
|
||||
# ```
|
||||
# FIXME(ztombol): Display `${lines[@]}' instead of `$output'!
|
||||
assert_line() {
|
||||
local -i is_match_line=0
|
||||
local -i is_mode_partial=0
|
||||
local -i is_mode_regexp=0
|
||||
: "${lines?}"
|
||||
|
||||
# Handle options.
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
-n|--index)
|
||||
if (( $# < 2 )) || ! [[ $2 =~ ^-?([0-9]|[1-9][0-9]+)$ ]]; then
|
||||
echo "\`--index' requires an integer argument: \`$2'" \
|
||||
| batslib_decorate 'ERROR: assert_line' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
is_match_line=1
|
||||
local -ri idx="$2"
|
||||
shift 2
|
||||
;;
|
||||
-p|--partial) is_mode_partial=1; shift ;;
|
||||
-e|--regexp) is_mode_regexp=1; shift ;;
|
||||
--) shift; break ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if (( is_mode_partial )) && (( is_mode_regexp )); then
|
||||
echo "\`--partial' and \`--regexp' are mutually exclusive" \
|
||||
| batslib_decorate 'ERROR: assert_line' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Arguments.
|
||||
local -r expected="$1"
|
||||
|
||||
if (( is_mode_regexp == 1 )) && [[ '' =~ $expected ]] || (( $? == 2 )); then
|
||||
echo "Invalid extended regular expression: \`$expected'" \
|
||||
| batslib_decorate 'ERROR: assert_line' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Matching.
|
||||
if (( is_match_line )); then
|
||||
# Specific line.
|
||||
if (( is_mode_regexp )); then
|
||||
if ! [[ ${lines[$idx]} =~ $expected ]]; then
|
||||
batslib_print_kv_single 6 \
|
||||
'index' "$idx" \
|
||||
'regexp' "$expected" \
|
||||
'line' "${lines[$idx]}" \
|
||||
| batslib_decorate 'regular expression does not match line' \
|
||||
| fail
|
||||
fi
|
||||
elif (( is_mode_partial )); then
|
||||
if [[ ${lines[$idx]} != *"$expected"* ]]; then
|
||||
batslib_print_kv_single 9 \
|
||||
'index' "$idx" \
|
||||
'substring' "$expected" \
|
||||
'line' "${lines[$idx]}" \
|
||||
| batslib_decorate 'line does not contain substring' \
|
||||
| fail
|
||||
fi
|
||||
else
|
||||
if [[ ${lines[$idx]} != "$expected" ]]; then
|
||||
batslib_print_kv_single 8 \
|
||||
'index' "$idx" \
|
||||
'expected' "$expected" \
|
||||
'actual' "${lines[$idx]}" \
|
||||
| batslib_decorate 'line differs' \
|
||||
| fail
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Contained in output.
|
||||
if (( is_mode_regexp )); then
|
||||
local -i idx
|
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||
[[ ${lines[$idx]} =~ $expected ]] && return 0
|
||||
done
|
||||
{ local -ar single=( 'regexp' "$expected" )
|
||||
local -ar may_be_multi=( 'output' "$output" )
|
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||
batslib_print_kv_single "$width" "${single[@]}"
|
||||
batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}"
|
||||
} \
|
||||
| batslib_decorate 'no output line matches regular expression' \
|
||||
| fail
|
||||
elif (( is_mode_partial )); then
|
||||
local -i idx
|
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||
[[ ${lines[$idx]} == *"$expected"* ]] && return 0
|
||||
done
|
||||
{ local -ar single=( 'substring' "$expected" )
|
||||
local -ar may_be_multi=( 'output' "$output" )
|
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||
batslib_print_kv_single "$width" "${single[@]}"
|
||||
batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}"
|
||||
} \
|
||||
| batslib_decorate 'no output line contains substring' \
|
||||
| fail
|
||||
else
|
||||
local -i idx
|
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||
[[ ${lines[$idx]} == "$expected" ]] && return 0
|
||||
done
|
||||
{ local -ar single=( 'line' "$expected" )
|
||||
local -ar may_be_multi=( 'output' "$output" )
|
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||
batslib_print_kv_single "$width" "${single[@]}"
|
||||
batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}"
|
||||
} \
|
||||
| batslib_decorate 'output does not contain line' \
|
||||
| fail
|
||||
fi
|
||||
fi
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
# assert_not_equal
|
||||
# ============
|
||||
#
|
||||
# Summary: Fail if the actual and unexpected values are equal.
|
||||
#
|
||||
# Usage: assert_not_equal <actual> <unexpected>
|
||||
#
|
||||
# Options:
|
||||
# <actual> The value being compared.
|
||||
# <unexpected> The value to compare against.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_not_equal()' {
|
||||
# assert_not_equal 'foo' 'foo'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# IO:
|
||||
# STDERR - expected and actual values, on failure
|
||||
# Globals:
|
||||
# none
|
||||
# Returns:
|
||||
# 0 - if actual does not equal unexpected
|
||||
# 1 - otherwise
|
||||
#
|
||||
# On failure, the unexpected and actual values are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- values should not be equal --
|
||||
# unexpected : foo
|
||||
# actual : foo
|
||||
# --
|
||||
# ```
|
||||
assert_not_equal() {
|
||||
if [[ "$1" == "$2" ]]; then
|
||||
batslib_print_kv_single_or_multi 10 \
|
||||
'unexpected' "$2" \
|
||||
'actual' "$1" \
|
||||
| batslib_decorate 'values should not be equal' \
|
||||
| fail
|
||||
fi
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
# assert_output
|
||||
# =============
|
||||
#
|
||||
# Summary: Fail if `$output' does not match the expected output.
|
||||
#
|
||||
# Usage: assert_output [-p | -e] [- | [--] <expected>]
|
||||
#
|
||||
# Options:
|
||||
# -p, --partial Match if `expected` is a substring of `$output`
|
||||
# -e, --regexp Treat `expected` as an extended regular expression
|
||||
# -, --stdin Read `expected` value from STDIN
|
||||
# <expected> The expected value, substring or regular expression
|
||||
#
|
||||
# IO:
|
||||
# STDIN - [=$1] expected output
|
||||
# STDERR - details, on failure
|
||||
# error message, on error
|
||||
# Globals:
|
||||
# output
|
||||
# Returns:
|
||||
# 0 - if output matches the expected value/partial/regexp
|
||||
# 1 - otherwise
|
||||
#
|
||||
# This function verifies that a command or function produces the expected output.
|
||||
# (It is the logical complement of `refute_output`.)
|
||||
# Output matching can be literal (the default), partial or by regular expression.
|
||||
# The expected output can be specified either by positional argument or read from STDIN by passing the `-`/`--stdin` flag.
|
||||
#
|
||||
# ## Literal matching
|
||||
#
|
||||
# By default, literal matching is performed.
|
||||
# The assertion fails if `$output` does not equal the expected output.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_output()' {
|
||||
# run echo 'have'
|
||||
# assert_output 'want'
|
||||
# }
|
||||
#
|
||||
# @test 'assert_output() with pipe' {
|
||||
# run echo 'hello'
|
||||
# echo 'hello' | assert_output -
|
||||
# }
|
||||
#
|
||||
# @test 'assert_output() with herestring' {
|
||||
# run echo 'hello'
|
||||
# assert_output - <<< hello
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the expected and actual output are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- output differs --
|
||||
# expected : want
|
||||
# actual : have
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Existence
|
||||
#
|
||||
# To assert that any output exists at all, omit the `expected` argument.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_output()' {
|
||||
# run echo 'have'
|
||||
# assert_output
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, an error message is displayed.
|
||||
#
|
||||
# ```
|
||||
# -- no output --
|
||||
# expected non-empty output, but output was empty
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Partial matching
|
||||
#
|
||||
# Partial matching can be enabled with the `--partial` option (`-p` for short).
|
||||
# When used, the assertion fails if the expected _substring_ is not found in `$output`.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_output() partial matching' {
|
||||
# run echo 'ERROR: no such file or directory'
|
||||
# assert_output --partial 'SUCCESS'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the substring and the output are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- output does not contain substring --
|
||||
# substring : SUCCESS
|
||||
# output : ERROR: no such file or directory
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Regular expression matching
|
||||
#
|
||||
# Regular expression matching can be enabled with the `--regexp` option (`-e` for short).
|
||||
# When used, the assertion fails if the *extended regular expression* does not match `$output`.
|
||||
#
|
||||
# *__Note__:
|
||||
# The anchors `^` and `$` bind to the beginning and the end (respectively) of the entire output;
|
||||
# not individual lines.*
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_output() regular expression matching' {
|
||||
# run echo 'Foobar 0.1.0'
|
||||
# assert_output --regexp '^Foobar v[0-9]+\.[0-9]+\.[0-9]$'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the regular expression and the output are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- regular expression does not match output --
|
||||
# regexp : ^Foobar v[0-9]+\.[0-9]+\.[0-9]$
|
||||
# output : Foobar 0.1.0
|
||||
# --
|
||||
# ```
|
||||
assert_output() {
|
||||
local -i is_mode_partial=0
|
||||
local -i is_mode_regexp=0
|
||||
local -i is_mode_nonempty=0
|
||||
local -i use_stdin=0
|
||||
: "${output?}"
|
||||
|
||||
# Handle options.
|
||||
if (( $# == 0 )); then
|
||||
is_mode_nonempty=1
|
||||
fi
|
||||
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
-p|--partial) is_mode_partial=1; shift ;;
|
||||
-e|--regexp) is_mode_regexp=1; shift ;;
|
||||
-|--stdin) use_stdin=1; shift ;;
|
||||
--) shift; break ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if (( is_mode_partial )) && (( is_mode_regexp )); then
|
||||
echo "\`--partial' and \`--regexp' are mutually exclusive" \
|
||||
| batslib_decorate 'ERROR: assert_output' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Arguments.
|
||||
local expected
|
||||
if (( use_stdin )); then
|
||||
expected="$(cat -)"
|
||||
else
|
||||
expected="${1-}"
|
||||
fi
|
||||
|
||||
# Matching.
|
||||
if (( is_mode_nonempty )); then
|
||||
if [ -z "$output" ]; then
|
||||
echo 'expected non-empty output, but output was empty' \
|
||||
| batslib_decorate 'no output' \
|
||||
| fail
|
||||
fi
|
||||
elif (( is_mode_regexp )); then
|
||||
if [[ '' =~ $expected ]] || (( $? == 2 )); then
|
||||
echo "Invalid extended regular expression: \`$expected'" \
|
||||
| batslib_decorate 'ERROR: assert_output' \
|
||||
| fail
|
||||
elif ! [[ $output =~ $expected ]]; then
|
||||
batslib_print_kv_single_or_multi 6 \
|
||||
'regexp' "$expected" \
|
||||
'output' "$output" \
|
||||
| batslib_decorate 'regular expression does not match output' \
|
||||
| fail
|
||||
fi
|
||||
elif (( is_mode_partial )); then
|
||||
if [[ $output != *"$expected"* ]]; then
|
||||
batslib_print_kv_single_or_multi 9 \
|
||||
'substring' "$expected" \
|
||||
'output' "$output" \
|
||||
| batslib_decorate 'output does not contain substring' \
|
||||
| fail
|
||||
fi
|
||||
else
|
||||
if [[ $output != "$expected" ]]; then
|
||||
batslib_print_kv_single_or_multi 8 \
|
||||
'expected' "$expected" \
|
||||
'actual' "$output" \
|
||||
| batslib_decorate 'output differs' \
|
||||
| fail
|
||||
fi
|
||||
fi
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
# `assert_regex`
|
||||
#
|
||||
# This function is similar to `assert_equal` but uses pattern matching instead
|
||||
# of equality, by wrapping `[[ value =~ pattern ]]`.
|
||||
#
|
||||
# Fail if the value (first parameter) does not match the pattern (second
|
||||
# parameter).
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_regex()' {
|
||||
# assert_regex 'what' 'x$'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the value and the pattern are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- values does not match regular expression --
|
||||
# value : what
|
||||
# pattern : x$
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# If the value is longer than one line then it is displayed in *multi-line*
|
||||
# format.
|
||||
#
|
||||
# An error is displayed if the specified extended regular expression is invalid.
|
||||
#
|
||||
# For description of the matching behavior, refer to the documentation of the
|
||||
# `=~` operator in the
|
||||
# [Bash manual]: https://www.gnu.org/software/bash/manual/html_node/Conditional-Constructs.html.
|
||||
# Note that the `BASH_REMATCH` array is available immediately after the
|
||||
# assertion succeeds but is fragile, i.e. prone to being overwritten as a side
|
||||
# effect of other actions.
|
||||
assert_regex() {
|
||||
local -r value="${1}"
|
||||
local -r pattern="${2}"
|
||||
|
||||
if [[ '' =~ ${pattern} ]] || (( ${?} == 2 )); then
|
||||
echo "Invalid extended regular expression: \`${pattern}'" \
|
||||
| batslib_decorate 'ERROR: assert_regex' \
|
||||
| fail
|
||||
elif ! [[ "${value}" =~ ${pattern} ]]; then
|
||||
if shopt -p nocasematch &>/dev/null; then
|
||||
local case_sensitive=insensitive
|
||||
else
|
||||
local case_sensitive=sensitive
|
||||
fi
|
||||
batslib_print_kv_single_or_multi 8 \
|
||||
'value' "${value}" \
|
||||
'pattern' "${pattern}" \
|
||||
'case' "${case_sensitive}" \
|
||||
| batslib_decorate 'value does not match regular expression' \
|
||||
| fail
|
||||
fi
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
# assert_success
|
||||
# ==============
|
||||
#
|
||||
# Summary: Fail if `$status` is not 0.
|
||||
#
|
||||
# Usage: assert_success
|
||||
#
|
||||
# IO:
|
||||
# STDERR - `$status` and `$output`, on failure
|
||||
# Globals:
|
||||
# status
|
||||
# output
|
||||
# Returns:
|
||||
# 0 - if `$status' is 0
|
||||
# 1 - otherwise
|
||||
#
|
||||
# ```bash
|
||||
# @test 'assert_success() status only' {
|
||||
# run bash -c "echo 'Error!'; exit 1"
|
||||
# assert_success
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, `$status` and `$output` are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- command failed --
|
||||
# status : 1
|
||||
# output : Error!
|
||||
# --
|
||||
# ```
|
||||
assert_success() {
|
||||
: "${output?}"
|
||||
: "${status?}"
|
||||
|
||||
if (( status != 0 )); then
|
||||
{ local -ir width=6
|
||||
batslib_print_kv_single "$width" 'status' "$status"
|
||||
batslib_print_kv_single_or_multi "$width" 'output' "$output"
|
||||
} \
|
||||
| batslib_decorate 'command failed' \
|
||||
| fail
|
||||
fi
|
||||
}
|
42
extras/portable/test/test_helper/bats-assert/src/refute.bash
Normal file
42
extras/portable/test/test_helper/bats-assert/src/refute.bash
Normal file
@ -0,0 +1,42 @@
|
||||
# refute
|
||||
# ======
|
||||
#
|
||||
# Summary: Fail if the given expression evaluates to true.
|
||||
#
|
||||
# Usage: refute <expression>
|
||||
#
|
||||
# Options:
|
||||
# <expression> The expression to evaluate for falsiness.
|
||||
# *__Note:__ The expression must be a simple command.
|
||||
# [Compound commands](https://www.gnu.org/software/bash/manual/bash.html#Compound-Commands),
|
||||
# such as `[[`, can be used only when executed with `bash -c`.*
|
||||
#
|
||||
# IO:
|
||||
# STDERR - the successful expression, on failure
|
||||
# Globals:
|
||||
# none
|
||||
# Returns:
|
||||
# 0 - if expression evaluates to false
|
||||
# 1 - otherwise
|
||||
#
|
||||
# ```bash
|
||||
# @test 'refute()' {
|
||||
# rm -f '/var/log/test.log'
|
||||
# refute [ -e '/var/log/test.log' ]
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the successful expression is displayed.
|
||||
#
|
||||
# ```
|
||||
# -- assertion succeeded, but it was expected to fail --
|
||||
# expression : [ -e /var/log/test.log ]
|
||||
# --
|
||||
# ```
|
||||
refute() {
|
||||
if "$@"; then
|
||||
batslib_print_kv_single 10 'expression' "$*" \
|
||||
| batslib_decorate 'assertion succeeded, but it was expected to fail' \
|
||||
| fail
|
||||
fi
|
||||
}
|
@ -0,0 +1,271 @@
|
||||
# refute_line
|
||||
# ===========
|
||||
#
|
||||
# Summary: Fail if the unexpected line is found in the output (default) or at a specific line number.
|
||||
#
|
||||
# Usage: refute_line [-n index] [-p | -e] [--] <unexpected>
|
||||
#
|
||||
# Options:
|
||||
# -n, --index <idx> Match the <idx>th line
|
||||
# -p, --partial Match if `unexpected` is a substring of `$output` or line <idx>
|
||||
# -e, --regexp Treat `unexpected` as an extended regular expression
|
||||
# <unexpected> The unexpected line string, substring, or regular expression.
|
||||
#
|
||||
# IO:
|
||||
# STDERR - details, on failure
|
||||
# error message, on error
|
||||
# Globals:
|
||||
# output
|
||||
# lines
|
||||
# Returns:
|
||||
# 0 - if match not found
|
||||
# 1 - otherwise
|
||||
#
|
||||
# Similarly to `refute_output`, this function verifies that a command or function does not produce the unexpected output.
|
||||
# (It is the logical complement of `assert_line`.)
|
||||
# It checks that the unexpected line does not appear in the output (default) or at a specific line number.
|
||||
# Matching can be literal (default), partial or regular expression.
|
||||
#
|
||||
# *__Warning:__
|
||||
# Due to a [bug in Bats][bats-93], empty lines are discarded from `${lines[@]}`,
|
||||
# causing line indices to change and preventing testing for empty lines.*
|
||||
#
|
||||
# [bats-93]: https://github.com/sstephenson/bats/pull/93
|
||||
#
|
||||
# ## Looking for a line in the output
|
||||
#
|
||||
# By default, the entire output is searched for the unexpected line.
|
||||
# The assertion fails if the unexpected line is found in `${lines[@]}`.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'refute_line() looking for line' {
|
||||
# run echo $'have-0\nwant\nhave-2'
|
||||
# refute_line 'want'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the unexpected line, the index of its first match and the output with the matching line highlighted are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- line should not be in output --
|
||||
# line : want
|
||||
# index : 1
|
||||
# output (3 lines):
|
||||
# have-0
|
||||
# > want
|
||||
# have-2
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Matching a specific line
|
||||
#
|
||||
# When the `--index <idx>` option is used (`-n <idx>` for short), the unexpected line is matched only against the line identified by the given index.
|
||||
# The assertion fails if the unexpected line equals `${lines[<idx>]}`.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'refute_line() specific line' {
|
||||
# run echo $'have-0\nwant-1\nhave-2'
|
||||
# refute_line --index 1 'want-1'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the index and the unexpected line are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- line should differ --
|
||||
# index : 1
|
||||
# line : want-1
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Partial matching
|
||||
#
|
||||
# Partial matching can be enabled with the `--partial` option (`-p` for short).
|
||||
# When used, a match fails if the unexpected *substring* is found in the matched line.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'refute_line() partial matching' {
|
||||
# run echo $'have 1\nwant 2\nhave 3'
|
||||
# refute_line --partial 'want'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, in addition to the details of literal matching, the substring is also displayed.
|
||||
# When used with `--index <idx>` the substring replaces the unexpected line.
|
||||
#
|
||||
# ```
|
||||
# -- no line should contain substring --
|
||||
# substring : want
|
||||
# index : 1
|
||||
# output (3 lines):
|
||||
# have 1
|
||||
# > want 2
|
||||
# have 3
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Regular expression matching
|
||||
#
|
||||
# Regular expression matching can be enabled with the `--regexp` option (`-e` for short).
|
||||
# When used, a match fails if the *extended regular expression* matches the line being tested.
|
||||
#
|
||||
# *__Note__:
|
||||
# As expected, the anchors `^` and `$` bind to the beginning and the end (respectively) of the matched line.*
|
||||
#
|
||||
# ```bash
|
||||
# @test 'refute_line() regular expression matching' {
|
||||
# run echo $'Foobar v0.1.0\nRelease date: 2015-11-29'
|
||||
# refute_line --index 0 --regexp '^Foobar v[0-9]+\.[0-9]+\.[0-9]$'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, in addition to the details of literal matching, the regular expression is also displayed.
|
||||
# When used with `--index <idx>` the regular expression replaces the unexpected line.
|
||||
#
|
||||
# ```
|
||||
# -- regular expression should not match line --
|
||||
# index : 0
|
||||
# regexp : ^Foobar v[0-9]+\.[0-9]+\.[0-9]$
|
||||
# line : Foobar v0.1.0
|
||||
# --
|
||||
# ```
|
||||
# FIXME(ztombol): Display `${lines[@]}' instead of `$output'!
|
||||
refute_line() {
|
||||
local -i is_match_line=0
|
||||
local -i is_mode_partial=0
|
||||
local -i is_mode_regexp=0
|
||||
: "${lines?}"
|
||||
|
||||
# Handle options.
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
-n|--index)
|
||||
if (( $# < 2 )) || ! [[ $2 =~ ^-?([0-9]|[1-9][0-9]+)$ ]]; then
|
||||
echo "\`--index' requires an integer argument: \`$2'" \
|
||||
| batslib_decorate 'ERROR: refute_line' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
is_match_line=1
|
||||
local -ri idx="$2"
|
||||
shift 2
|
||||
;;
|
||||
-p|--partial) is_mode_partial=1; shift ;;
|
||||
-e|--regexp) is_mode_regexp=1; shift ;;
|
||||
--) shift; break ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if (( is_mode_partial )) && (( is_mode_regexp )); then
|
||||
echo "\`--partial' and \`--regexp' are mutually exclusive" \
|
||||
| batslib_decorate 'ERROR: refute_line' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Arguments.
|
||||
local -r unexpected="$1"
|
||||
|
||||
if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then
|
||||
echo "Invalid extended regular expression: \`$unexpected'" \
|
||||
| batslib_decorate 'ERROR: refute_line' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Matching.
|
||||
if (( is_match_line )); then
|
||||
# Specific line.
|
||||
if (( is_mode_regexp )); then
|
||||
if [[ ${lines[$idx]} =~ $unexpected ]]; then
|
||||
batslib_print_kv_single 6 \
|
||||
'index' "$idx" \
|
||||
'regexp' "$unexpected" \
|
||||
'line' "${lines[$idx]}" \
|
||||
| batslib_decorate 'regular expression should not match line' \
|
||||
| fail
|
||||
fi
|
||||
elif (( is_mode_partial )); then
|
||||
if [[ ${lines[$idx]} == *"$unexpected"* ]]; then
|
||||
batslib_print_kv_single 9 \
|
||||
'index' "$idx" \
|
||||
'substring' "$unexpected" \
|
||||
'line' "${lines[$idx]}" \
|
||||
| batslib_decorate 'line should not contain substring' \
|
||||
| fail
|
||||
fi
|
||||
else
|
||||
if [[ ${lines[$idx]} == "$unexpected" ]]; then
|
||||
batslib_print_kv_single 5 \
|
||||
'index' "$idx" \
|
||||
'line' "${lines[$idx]}" \
|
||||
| batslib_decorate 'line should differ' \
|
||||
| fail
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Line contained in output.
|
||||
if (( is_mode_regexp )); then
|
||||
local -i idx
|
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||
if [[ ${lines[$idx]} =~ $unexpected ]]; then
|
||||
{ local -ar single=( 'regexp' "$unexpected" 'index' "$idx" )
|
||||
local -a may_be_multi=( 'output' "$output" )
|
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||
batslib_print_kv_single "$width" "${single[@]}"
|
||||
if batslib_is_single_line "${may_be_multi[1]}"; then
|
||||
batslib_print_kv_single "$width" "${may_be_multi[@]}"
|
||||
else
|
||||
may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )"
|
||||
batslib_print_kv_multi "${may_be_multi[@]}"
|
||||
fi
|
||||
} \
|
||||
| batslib_decorate 'no line should match the regular expression' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
done
|
||||
elif (( is_mode_partial )); then
|
||||
local -i idx
|
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||
if [[ ${lines[$idx]} == *"$unexpected"* ]]; then
|
||||
{ local -ar single=( 'substring' "$unexpected" 'index' "$idx" )
|
||||
local -a may_be_multi=( 'output' "$output" )
|
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||
batslib_print_kv_single "$width" "${single[@]}"
|
||||
if batslib_is_single_line "${may_be_multi[1]}"; then
|
||||
batslib_print_kv_single "$width" "${may_be_multi[@]}"
|
||||
else
|
||||
may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )"
|
||||
batslib_print_kv_multi "${may_be_multi[@]}"
|
||||
fi
|
||||
} \
|
||||
| batslib_decorate 'no line should contain substring' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
done
|
||||
else
|
||||
local -i idx
|
||||
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||
if [[ ${lines[$idx]} == "$unexpected" ]]; then
|
||||
{ local -ar single=( 'line' "$unexpected" 'index' "$idx" )
|
||||
local -a may_be_multi=( 'output' "$output" )
|
||||
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||
batslib_print_kv_single "$width" "${single[@]}"
|
||||
if batslib_is_single_line "${may_be_multi[1]}"; then
|
||||
batslib_print_kv_single "$width" "${may_be_multi[@]}"
|
||||
else
|
||||
may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )"
|
||||
batslib_print_kv_multi "${may_be_multi[@]}"
|
||||
fi
|
||||
} \
|
||||
| batslib_decorate 'line should not be in output' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
# refute_output
|
||||
# =============
|
||||
#
|
||||
# Summary: Fail if `$output' matches the unexpected output.
|
||||
#
|
||||
# Usage: refute_output [-p | -e] [- | [--] <unexpected>]
|
||||
#
|
||||
# Options:
|
||||
# -p, --partial Match if `unexpected` is a substring of `$output`
|
||||
# -e, --regexp Treat `unexpected` as an extended regular expression
|
||||
# -, --stdin Read `unexpected` value from STDIN
|
||||
# <unexpected> The unexpected value, substring, or regular expression
|
||||
#
|
||||
# IO:
|
||||
# STDIN - [=$1] unexpected output
|
||||
# STDERR - details, on failure
|
||||
# error message, on error
|
||||
# Globals:
|
||||
# output
|
||||
# Returns:
|
||||
# 0 - if output matches the unexpected value/partial/regexp
|
||||
# 1 - otherwise
|
||||
#
|
||||
# This function verifies that a command or function does not produce the unexpected output.
|
||||
# (It is the logical complement of `assert_output`.)
|
||||
# Output matching can be literal (the default), partial or by regular expression.
|
||||
# The unexpected output can be specified either by positional argument or read from STDIN by passing the `-`/`--stdin` flag.
|
||||
#
|
||||
# ## Literal matching
|
||||
#
|
||||
# By default, literal matching is performed.
|
||||
# The assertion fails if `$output` equals the unexpected output.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'refute_output()' {
|
||||
# run echo 'want'
|
||||
# refute_output 'want'
|
||||
# }
|
||||
#
|
||||
# @test 'refute_output() with pipe' {
|
||||
# run echo 'hello'
|
||||
# echo 'world' | refute_output -
|
||||
# }
|
||||
#
|
||||
# @test 'refute_output() with herestring' {
|
||||
# run echo 'hello'
|
||||
# refute_output - <<< world
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the output is displayed.
|
||||
#
|
||||
# ```
|
||||
# -- output equals, but it was expected to differ --
|
||||
# output : want
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Existence
|
||||
#
|
||||
# To assert that there is no output at all, omit the matching argument.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'refute_output()' {
|
||||
# run foo --silent
|
||||
# refute_output
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, an error message is displayed.
|
||||
#
|
||||
# ```
|
||||
# -- unexpected output --
|
||||
# expected no output, but output was non-empty
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Partial matching
|
||||
#
|
||||
# Partial matching can be enabled with the `--partial` option (`-p` for short).
|
||||
# When used, the assertion fails if the unexpected _substring_ is found in `$output`.
|
||||
#
|
||||
# ```bash
|
||||
# @test 'refute_output() partial matching' {
|
||||
# run echo 'ERROR: no such file or directory'
|
||||
# refute_output --partial 'ERROR'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the substring and the output are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- output should not contain substring --
|
||||
# substring : ERROR
|
||||
# output : ERROR: no such file or directory
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# ## Regular expression matching
|
||||
#
|
||||
# Regular expression matching can be enabled with the `--regexp` option (`-e` for short).
|
||||
# When used, the assertion fails if the *extended regular expression* matches `$output`.
|
||||
#
|
||||
# *__Note__:
|
||||
# The anchors `^` and `$` bind to the beginning and the end (respectively) of the entire output;
|
||||
# not individual lines.*
|
||||
#
|
||||
# ```bash
|
||||
# @test 'refute_output() regular expression matching' {
|
||||
# run echo 'Foobar v0.1.0'
|
||||
# refute_output --regexp '^Foobar v[0-9]+\.[0-9]+\.[0-9]$'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the regular expression and the output are displayed.
|
||||
#
|
||||
# ```
|
||||
# -- regular expression should not match output --
|
||||
# regexp : ^Foobar v[0-9]+\.[0-9]+\.[0-9]$
|
||||
# output : Foobar v0.1.0
|
||||
# --
|
||||
# ```
|
||||
refute_output() {
|
||||
local -i is_mode_partial=0
|
||||
local -i is_mode_regexp=0
|
||||
local -i is_mode_empty=0
|
||||
local -i use_stdin=0
|
||||
: "${output?}"
|
||||
|
||||
# Handle options.
|
||||
if (( $# == 0 )); then
|
||||
is_mode_empty=1
|
||||
fi
|
||||
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
-p|--partial) is_mode_partial=1; shift ;;
|
||||
-e|--regexp) is_mode_regexp=1; shift ;;
|
||||
-|--stdin) use_stdin=1; shift ;;
|
||||
--) shift; break ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if (( is_mode_partial )) && (( is_mode_regexp )); then
|
||||
echo "\`--partial' and \`--regexp' are mutually exclusive" \
|
||||
| batslib_decorate 'ERROR: refute_output' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Arguments.
|
||||
local unexpected
|
||||
if (( use_stdin )); then
|
||||
unexpected="$(cat -)"
|
||||
else
|
||||
unexpected="${1-}"
|
||||
fi
|
||||
|
||||
if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then
|
||||
echo "Invalid extended regular expression: \`$unexpected'" \
|
||||
| batslib_decorate 'ERROR: refute_output' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Matching.
|
||||
if (( is_mode_empty )); then
|
||||
if [ -n "$output" ]; then
|
||||
batslib_print_kv_single_or_multi 6 \
|
||||
'output' "$output" \
|
||||
| batslib_decorate 'output non-empty, but expected no output' \
|
||||
| fail
|
||||
fi
|
||||
elif (( is_mode_regexp )); then
|
||||
if [[ $output =~ $unexpected ]]; then
|
||||
batslib_print_kv_single_or_multi 6 \
|
||||
'regexp' "$unexpected" \
|
||||
'output' "$output" \
|
||||
| batslib_decorate 'regular expression should not match output' \
|
||||
| fail
|
||||
fi
|
||||
elif (( is_mode_partial )); then
|
||||
if [[ $output == *"$unexpected"* ]]; then
|
||||
batslib_print_kv_single_or_multi 9 \
|
||||
'substring' "$unexpected" \
|
||||
'output' "$output" \
|
||||
| batslib_decorate 'output should not contain substring' \
|
||||
| fail
|
||||
fi
|
||||
else
|
||||
if [[ $output == "$unexpected" ]]; then
|
||||
batslib_print_kv_single_or_multi 6 \
|
||||
'output' "$output" \
|
||||
| batslib_decorate 'output equals, but it was expected to differ' \
|
||||
| fail
|
||||
fi
|
||||
fi
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
# `refute_regex`
|
||||
#
|
||||
# This function is similar to `refute_equal` but uses pattern matching instead
|
||||
# of equality, by wrapping `! [[ value =~ pattern ]]`.
|
||||
#
|
||||
# Fail if the value (first parameter) matches the pattern (second parameter).
|
||||
#
|
||||
# ```bash
|
||||
# @test 'refute_regex()' {
|
||||
# refute_regex 'WhatsApp' 'Threema'
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# On failure, the value, the pattern and the match are displayed.
|
||||
#
|
||||
# ```
|
||||
# @test 'refute_regex()' {
|
||||
# refute_regex 'WhatsApp' 'What.'
|
||||
# }
|
||||
#
|
||||
# -- value matches regular expression --
|
||||
# value : WhatsApp
|
||||
# pattern : What.
|
||||
# match : Whats
|
||||
# case : sensitive
|
||||
# --
|
||||
# ```
|
||||
#
|
||||
# If the value or pattern is longer than one line then it is displayed in
|
||||
# *multi-line* format.
|
||||
#
|
||||
# An error is displayed if the specified extended regular expression is invalid.
|
||||
#
|
||||
# For description of the matching behavior, refer to the documentation of the
|
||||
# `=~` operator in the
|
||||
# [Bash manual]: https://www.gnu.org/software/bash/manual/html_node/Conditional-Constructs.html.
|
||||
#
|
||||
# Note that the `BASH_REMATCH` array is available immediately after the
|
||||
# assertion fails but is fragile, i.e. prone to being overwritten as a side
|
||||
# effect of other actions like calling `run`. Thus, it's good practice to avoid
|
||||
# using `BASH_REMATCH` in conjunction with `refute_regex()`. The valuable
|
||||
# information the array contains is the matching part of the value which is
|
||||
# printed in the failing test log, as mentioned above.
|
||||
refute_regex() {
|
||||
local -r value="${1}"
|
||||
local -r pattern="${2}"
|
||||
|
||||
if [[ '' =~ ${pattern} ]] || (( ${?} == 2 )); then
|
||||
echo "Invalid extended regular expression: \`${pattern}'" \
|
||||
| batslib_decorate 'ERROR: refute_regex' \
|
||||
| fail
|
||||
elif [[ "${value}" =~ ${pattern} ]]; then
|
||||
if shopt -p nocasematch &>/dev/null; then
|
||||
local case_sensitive=insensitive
|
||||
else
|
||||
local case_sensitive=sensitive
|
||||
fi
|
||||
batslib_print_kv_single_or_multi 8 \
|
||||
'value' "${value}" \
|
||||
'pattern' "${pattern}" \
|
||||
'match' "${BASH_REMATCH[0]}" \
|
||||
'case' "${case_sensitive}" \
|
||||
| batslib_decorate 'value matches regular expression' \
|
||||
| fail
|
||||
fi
|
||||
}
|
2
extras/portable/test/test_helper/bats-file/load.bash
Normal file
2
extras/portable/test/test_helper/bats-file/load.bash
Normal file
@ -0,0 +1,2 @@
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/file.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/temp.bash"
|
1111
extras/portable/test/test_helper/bats-file/src/file.bash
Normal file
1111
extras/portable/test/test_helper/bats-file/src/file.bash
Normal file
File diff suppressed because it is too large
Load Diff
182
extras/portable/test/test_helper/bats-file/src/temp.bash
Executable file
182
extras/portable/test/test_helper/bats-file/src/temp.bash
Executable file
@ -0,0 +1,182 @@
|
||||
#
|
||||
# bats-file - Common filesystem assertions and helpers for Bats
|
||||
#
|
||||
# Written in 2016 by Zoltan Tombol <zoltan dot tombol at gmail dot com>
|
||||
#
|
||||
# To the extent possible under law, the author(s) have dedicated all
|
||||
# copyright and related and neighboring rights to this software to the
|
||||
# public domain worldwide. This software is distributed without any
|
||||
# warranty.
|
||||
#
|
||||
# You should have received a copy of the CC0 Public Domain Dedication
|
||||
# along with this software. If not, see
|
||||
# <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
#
|
||||
|
||||
#
|
||||
# temp.bash
|
||||
# ---------
|
||||
#
|
||||
# Functions for handling temporary directories.
|
||||
#
|
||||
|
||||
# Create a temporary directory for the current test in `BATS_TMPDIR`,
|
||||
# and display its path on the standard output.
|
||||
#
|
||||
# The directory name is derived from the test's filename and number, and
|
||||
# a random string for uniqueness.
|
||||
#
|
||||
# <test-filename>-<test-number>-<random-string>
|
||||
#
|
||||
# When `--prefix <prefix>' is specified, `<prefix>' is prepended to the
|
||||
# directory name.
|
||||
#
|
||||
# <prefix><test-filename>-<test-number>-<random-string>
|
||||
#
|
||||
# Must be called from `setup', `@test' or `teardown'.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# setup() {
|
||||
# TEST_TEMP_DIR="$(temp_make --prefix 'myapp-')"
|
||||
# }
|
||||
#
|
||||
# teardown() {
|
||||
# temp_del "$TEST_TEMP_DIR"
|
||||
# }
|
||||
#
|
||||
# Globals:
|
||||
# BATS_TEST_NAME
|
||||
# BATS_TEST_FILENAME
|
||||
# BATS_TEST_NUMBER
|
||||
# BATS_TMPDIR
|
||||
# Arguments:
|
||||
# none
|
||||
# Options:
|
||||
# -p, --prefix <prefix> - prefix the directory name with `<prefix>'
|
||||
# Returns:
|
||||
# 0 - on success
|
||||
# 1 - otherwise
|
||||
# Outputs:
|
||||
# STDOUT - path of temporary directory
|
||||
# STDERR - error messages
|
||||
temp_make() {
|
||||
# Check caller.
|
||||
if ! ( batslib_is_caller --indirect 'setup' \
|
||||
|| batslib_is_caller --indirect 'setup_file' \
|
||||
|| batslib_is_caller --indirect "$BATS_TEST_NAME" \
|
||||
|| batslib_is_caller --indirect 'teardown' \
|
||||
|| batslib_is_caller --indirect 'teardown_file' )
|
||||
then
|
||||
echo "Must be called from \`setup', \`@test' or \`teardown'" \
|
||||
| batslib_decorate 'ERROR: temp_make' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Handle options.
|
||||
local prefix=''
|
||||
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
-p|--prefix)
|
||||
if (( $# < 2 )); then
|
||||
echo "\`--prefix' requires an argument" \
|
||||
| batslib_decorate 'ERROR: temp_make' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
prefix="$2"
|
||||
shift 2
|
||||
;;
|
||||
--) shift; break ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Create directory.
|
||||
local template="$prefix"
|
||||
template+="${BATS_TEST_FILENAME##*/}"
|
||||
template+="-${BATS_TEST_NUMBER}"
|
||||
template+='-XXXXXXXXXX'
|
||||
|
||||
local path
|
||||
path="$(mktemp -d -- "${BATS_TMPDIR}/${template}" 2>&1)"
|
||||
if (( $? )); then
|
||||
echo "$path" \
|
||||
| batslib_decorate 'ERROR: temp_make' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
|
||||
echo "$path"
|
||||
}
|
||||
|
||||
# Delete a temporary directory, typically created with `temp_make', and
|
||||
# its contents.
|
||||
#
|
||||
# Note: Actually, this function can be used to delete any file or
|
||||
# directory. However, it is most useful in deleting temporary
|
||||
# directories created with `temp_make', hence the naming.
|
||||
#
|
||||
# For development and debugging, deletion can be prevented using
|
||||
# environment variables.
|
||||
#
|
||||
# When `BATSLIB_TEMP_PRESERVE' is set to 1, the function succeeds but
|
||||
# the directory is not deleted.
|
||||
#
|
||||
# When `BATSLIB_TEMP_PRESERVE_ON_FAILURE' is set to 1 and `temp_del' is
|
||||
# called, directly or indirectly, from `teardown', the function succeeds
|
||||
# but the directory is not deleted if the test has failed.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# setup() {
|
||||
# TEST_TEMP_DIR="$(temp_make --prefix 'myapp-')"
|
||||
# }
|
||||
#
|
||||
# teardown() {
|
||||
# temp_del "$TEST_TEMP_DIR"
|
||||
# }
|
||||
#
|
||||
# Globals:
|
||||
# BATSLIB_TEMP_PRESERVE
|
||||
# BATSLIB_TEMP_PRESERVE_ON_FAILURE
|
||||
# BATS_TEST_COMPLETED
|
||||
# Arguments:
|
||||
# $1 - path of directory
|
||||
# Returns:
|
||||
# 0 - on success
|
||||
# 1 - otherwise
|
||||
# Outputs:
|
||||
# STDERR - error messages
|
||||
temp_del() {
|
||||
local -r path="$1"
|
||||
|
||||
# Environment variables.
|
||||
if [[ ${BATSLIB_TEMP_PRESERVE-} == '1' ]]; then
|
||||
return 0
|
||||
elif [[ ${BATSLIB_TEMP_PRESERVE_ON_FAILURE-} == '1' ]]; then
|
||||
# Check caller.
|
||||
if ! ( batslib_is_caller --indirect 'teardown' \
|
||||
|| batslib_is_caller --indirect 'teardown_file' )
|
||||
then
|
||||
echo "Must be called from \`teardown' or \`teardown_file' when using \`BATSLIB_TEMP_PRESERVE_ON_FAILURE'" \
|
||||
| batslib_decorate 'ERROR: temp_del' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
|
||||
(( ${BATS_TEST_COMPLETED:-0} != 1 )) && return 0
|
||||
fi
|
||||
|
||||
# Delete directory.
|
||||
local result
|
||||
result="$(rm -r -- "$path" 2>&1 </dev/null)"
|
||||
if (( $? )); then
|
||||
echo "$result" \
|
||||
| batslib_decorate 'ERROR: temp_del' \
|
||||
| fail
|
||||
return $?
|
||||
fi
|
||||
}
|
3
extras/portable/test/test_helper/bats-support/load.bash
Normal file
3
extras/portable/test/test_helper/bats-support/load.bash
Normal file
@ -0,0 +1,3 @@
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/output.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/error.bash"
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/src/lang.bash"
|
41
extras/portable/test/test_helper/bats-support/src/error.bash
Normal file
41
extras/portable/test/test_helper/bats-support/src/error.bash
Normal file
@ -0,0 +1,41 @@
|
||||
#
|
||||
# bats-support - Supporting library for Bats test helpers
|
||||
#
|
||||
# Written in 2016 by Zoltan Tombol <zoltan dot tombol at gmail dot com>
|
||||
#
|
||||
# To the extent possible under law, the author(s) have dedicated all
|
||||
# copyright and related and neighboring rights to this software to the
|
||||
# public domain worldwide. This software is distributed without any
|
||||
# warranty.
|
||||
#
|
||||
# You should have received a copy of the CC0 Public Domain Dedication
|
||||
# along with this software. If not, see
|
||||
# <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
#
|
||||
|
||||
#
|
||||
# error.bash
|
||||
# ----------
|
||||
#
|
||||
# Functions implementing error reporting. Used by public helper
|
||||
# functions or test suits directly.
|
||||
#
|
||||
|
||||
# Fail and display a message. When no parameters are specified, the
|
||||
# message is read from the standard input. Other functions use this to
|
||||
# report failure.
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $@ - [=STDIN] message
|
||||
# Returns:
|
||||
# 1 - always
|
||||
# Inputs:
|
||||
# STDIN - [=$@] message
|
||||
# Outputs:
|
||||
# STDERR - message
|
||||
fail() {
|
||||
(( $# == 0 )) && batslib_err || batslib_err "$@"
|
||||
return 1
|
||||
}
|
73
extras/portable/test/test_helper/bats-support/src/lang.bash
Normal file
73
extras/portable/test/test_helper/bats-support/src/lang.bash
Normal file
@ -0,0 +1,73 @@
|
||||
#
|
||||
# bats-util - Various auxiliary functions for Bats
|
||||
#
|
||||
# Written in 2016 by Zoltan Tombol <zoltan dot tombol at gmail dot com>
|
||||
#
|
||||
# To the extent possible under law, the author(s) have dedicated all
|
||||
# copyright and related and neighboring rights to this software to the
|
||||
# public domain worldwide. This software is distributed without any
|
||||
# warranty.
|
||||
#
|
||||
# You should have received a copy of the CC0 Public Domain Dedication
|
||||
# along with this software. If not, see
|
||||
# <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
#
|
||||
|
||||
#
|
||||
# lang.bash
|
||||
# ---------
|
||||
#
|
||||
# Bash language and execution related functions. Used by public helper
|
||||
# functions.
|
||||
#
|
||||
|
||||
# Check whether the calling function was called from a given function.
|
||||
#
|
||||
# By default, direct invocation is checked. The function succeeds if the
|
||||
# calling function was called directly from the given function. In other
|
||||
# words, if the given function is the next element on the call stack.
|
||||
#
|
||||
# When `--indirect' is specified, indirect invocation is checked. The
|
||||
# function succeeds if the calling function was called from the given
|
||||
# function with any number of intermediate calls. In other words, if the
|
||||
# given function can be found somewhere on the call stack.
|
||||
#
|
||||
# Direct invocation is a form of indirect invocation with zero
|
||||
# intermediate calls.
|
||||
#
|
||||
# Globals:
|
||||
# FUNCNAME
|
||||
# Options:
|
||||
# -i, --indirect - check indirect invocation
|
||||
# Arguments:
|
||||
# $1 - calling function's name
|
||||
# Returns:
|
||||
# 0 - current function was called from the given function
|
||||
# 1 - otherwise
|
||||
batslib_is_caller() {
|
||||
local -i is_mode_direct=1
|
||||
|
||||
# Handle options.
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
-i|--indirect) is_mode_direct=0; shift ;;
|
||||
--) shift; break ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Arguments.
|
||||
local -r func="$1"
|
||||
|
||||
# Check call stack.
|
||||
if (( is_mode_direct )); then
|
||||
[[ $func == "${FUNCNAME[2]}" ]] && return 0
|
||||
else
|
||||
local -i depth
|
||||
for (( depth=2; depth<${#FUNCNAME[@]}; ++depth )); do
|
||||
[[ $func == "${FUNCNAME[$depth]}" ]] && return 0
|
||||
done
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
279
extras/portable/test/test_helper/bats-support/src/output.bash
Normal file
279
extras/portable/test/test_helper/bats-support/src/output.bash
Normal file
@ -0,0 +1,279 @@
|
||||
#
|
||||
# bats-support - Supporting library for Bats test helpers
|
||||
#
|
||||
# Written in 2016 by Zoltan Tombol <zoltan dot tombol at gmail dot com>
|
||||
#
|
||||
# To the extent possible under law, the author(s) have dedicated all
|
||||
# copyright and related and neighboring rights to this software to the
|
||||
# public domain worldwide. This software is distributed without any
|
||||
# warranty.
|
||||
#
|
||||
# You should have received a copy of the CC0 Public Domain Dedication
|
||||
# along with this software. If not, see
|
||||
# <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
#
|
||||
|
||||
#
|
||||
# output.bash
|
||||
# -----------
|
||||
#
|
||||
# Private functions implementing output formatting. Used by public
|
||||
# helper functions.
|
||||
#
|
||||
|
||||
# Print a message to the standard error. When no parameters are
|
||||
# specified, the message is read from the standard input.
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $@ - [=STDIN] message
|
||||
# Returns:
|
||||
# none
|
||||
# Inputs:
|
||||
# STDIN - [=$@] message
|
||||
# Outputs:
|
||||
# STDERR - message
|
||||
batslib_err() {
|
||||
{ if (( $# > 0 )); then
|
||||
echo "$@"
|
||||
else
|
||||
cat -
|
||||
fi
|
||||
} >&2
|
||||
}
|
||||
|
||||
# Count the number of lines in the given string.
|
||||
#
|
||||
# TODO(ztombol): Fix tests and remove this note after #93 is resolved!
|
||||
# NOTE: Due to a bug in Bats, `batslib_count_lines "$output"' does not
|
||||
# give the same result as `${#lines[@]}' when the output contains
|
||||
# empty lines.
|
||||
# See PR #93 (https://github.com/sstephenson/bats/pull/93).
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $1 - string
|
||||
# Returns:
|
||||
# none
|
||||
# Outputs:
|
||||
# STDOUT - number of lines
|
||||
batslib_count_lines() {
|
||||
local -i n_lines=0
|
||||
local line
|
||||
while IFS='' read -r line || [[ -n $line ]]; do
|
||||
(( ++n_lines ))
|
||||
done < <(printf '%s' "$1")
|
||||
echo "$n_lines"
|
||||
}
|
||||
|
||||
# Determine whether all strings are single-line.
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $@ - strings
|
||||
# Returns:
|
||||
# 0 - all strings are single-line
|
||||
# 1 - otherwise
|
||||
batslib_is_single_line() {
|
||||
for string in "$@"; do
|
||||
(( $(batslib_count_lines "$string") > 1 )) && return 1
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# Determine the length of the longest key that has a single-line value.
|
||||
#
|
||||
# This function is useful in determining the correct width of the key
|
||||
# column in two-column format when some keys may have multi-line values
|
||||
# and thus should be excluded.
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $odd - key
|
||||
# $even - value of the previous key
|
||||
# Returns:
|
||||
# none
|
||||
# Outputs:
|
||||
# STDOUT - length of longest key
|
||||
batslib_get_max_single_line_key_width() {
|
||||
local -i max_len=-1
|
||||
while (( $# != 0 )); do
|
||||
local -i key_len="${#1}"
|
||||
batslib_is_single_line "$2" && (( key_len > max_len )) && max_len="$key_len"
|
||||
shift 2
|
||||
done
|
||||
echo "$max_len"
|
||||
}
|
||||
|
||||
# Print key-value pairs in two-column format.
|
||||
#
|
||||
# Keys are displayed in the first column, and their corresponding values
|
||||
# in the second. To evenly line up values, the key column is fixed-width
|
||||
# and its width is specified with the first parameter (possibly computed
|
||||
# using `batslib_get_max_single_line_key_width').
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $1 - width of key column
|
||||
# $even - key
|
||||
# $odd - value of the previous key
|
||||
# Returns:
|
||||
# none
|
||||
# Outputs:
|
||||
# STDOUT - formatted key-value pairs
|
||||
batslib_print_kv_single() {
|
||||
local -ir col_width="$1"; shift
|
||||
while (( $# != 0 )); do
|
||||
printf '%-*s : %s\n' "$col_width" "$1" "$2"
|
||||
shift 2
|
||||
done
|
||||
}
|
||||
|
||||
# Print key-value pairs in multi-line format.
|
||||
#
|
||||
# The key is displayed first with the number of lines of its
|
||||
# corresponding value in parenthesis. Next, starting on the next line,
|
||||
# the value is displayed. For better readability, it is recommended to
|
||||
# indent values using `batslib_prefix'.
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $odd - key
|
||||
# $even - value of the previous key
|
||||
# Returns:
|
||||
# none
|
||||
# Outputs:
|
||||
# STDOUT - formatted key-value pairs
|
||||
batslib_print_kv_multi() {
|
||||
while (( $# != 0 )); do
|
||||
printf '%s (%d lines):\n' "$1" "$( batslib_count_lines "$2" )"
|
||||
printf '%s\n' "$2"
|
||||
shift 2
|
||||
done
|
||||
}
|
||||
|
||||
# Print all key-value pairs in either two-column or multi-line format
|
||||
# depending on whether all values are single-line.
|
||||
#
|
||||
# If all values are single-line, print all pairs in two-column format
|
||||
# with the specified key column width (identical to using
|
||||
# `batslib_print_kv_single').
|
||||
#
|
||||
# Otherwise, print all pairs in multi-line format after indenting values
|
||||
# with two spaces for readability (identical to using `batslib_prefix'
|
||||
# and `batslib_print_kv_multi')
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $1 - width of key column (for two-column format)
|
||||
# $even - key
|
||||
# $odd - value of the previous key
|
||||
# Returns:
|
||||
# none
|
||||
# Outputs:
|
||||
# STDOUT - formatted key-value pairs
|
||||
batslib_print_kv_single_or_multi() {
|
||||
local -ir width="$1"; shift
|
||||
local -a pairs=( "$@" )
|
||||
|
||||
local -a values=()
|
||||
local -i i
|
||||
for (( i=1; i < ${#pairs[@]}; i+=2 )); do
|
||||
values+=( "${pairs[$i]}" )
|
||||
done
|
||||
|
||||
if batslib_is_single_line "${values[@]}"; then
|
||||
batslib_print_kv_single "$width" "${pairs[@]}"
|
||||
else
|
||||
local -i i
|
||||
for (( i=1; i < ${#pairs[@]}; i+=2 )); do
|
||||
pairs[$i]="$( batslib_prefix < <(printf '%s' "${pairs[$i]}") )"
|
||||
done
|
||||
batslib_print_kv_multi "${pairs[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Prefix each line read from the standard input with the given string.
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $1 - [= ] prefix string
|
||||
# Returns:
|
||||
# none
|
||||
# Inputs:
|
||||
# STDIN - lines
|
||||
# Outputs:
|
||||
# STDOUT - prefixed lines
|
||||
batslib_prefix() {
|
||||
local -r prefix="${1:- }"
|
||||
local line
|
||||
while IFS='' read -r line || [[ -n $line ]]; do
|
||||
printf '%s%s\n' "$prefix" "$line"
|
||||
done
|
||||
}
|
||||
|
||||
# Mark select lines of the text read from the standard input by
|
||||
# overwriting their beginning with the given string.
|
||||
#
|
||||
# Usually the input is indented by a few spaces using `batslib_prefix'
|
||||
# first.
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $1 - marking string
|
||||
# $@ - indices (zero-based) of lines to mark
|
||||
# Returns:
|
||||
# none
|
||||
# Inputs:
|
||||
# STDIN - lines
|
||||
# Outputs:
|
||||
# STDOUT - lines after marking
|
||||
batslib_mark() {
|
||||
local -r symbol="$1"; shift
|
||||
# Sort line numbers.
|
||||
set -- $( sort -nu <<< "$( printf '%d\n' "$@" )" )
|
||||
|
||||
local line
|
||||
local -i idx=0
|
||||
while IFS='' read -r line || [[ -n $line ]]; do
|
||||
if (( ${1:--1} == idx )); then
|
||||
printf '%s\n' "${symbol}${line:${#symbol}}"
|
||||
shift
|
||||
else
|
||||
printf '%s\n' "$line"
|
||||
fi
|
||||
(( ++idx ))
|
||||
done
|
||||
}
|
||||
|
||||
# Enclose the input text in header and footer lines.
|
||||
#
|
||||
# The header contains the given string as title. The output is preceded
|
||||
# and followed by an additional newline to make it stand out more.
|
||||
#
|
||||
# Globals:
|
||||
# none
|
||||
# Arguments:
|
||||
# $1 - title
|
||||
# Returns:
|
||||
# none
|
||||
# Inputs:
|
||||
# STDIN - text
|
||||
# Outputs:
|
||||
# STDOUT - decorated text
|
||||
batslib_decorate() {
|
||||
echo
|
||||
echo "-- $1 --"
|
||||
cat -
|
||||
echo '--'
|
||||
echo
|
||||
}
|
403
extras/portable/tomb
Executable file
403
extras/portable/tomb
Executable file
@ -0,0 +1,403 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Tomb v3, the Crypto Undertaker portable version 3
|
||||
#
|
||||
# A commandline tool to easily operate encryption of secret data
|
||||
#
|
||||
# {{{ License
|
||||
|
||||
# Copyright (C) 2007-2022 Dyne.org Foundation
|
||||
#
|
||||
# Tomb is designed, written and maintained by Denis Roio <jaromil@dyne.org>
|
||||
#
|
||||
# Please refer to the AUTHORS file for more information.
|
||||
#
|
||||
# This source code is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Please refer
|
||||
# to the GNU Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Public License along with
|
||||
# this source code; if not, , see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# }}} - License
|
||||
|
||||
# {{{ Global variables
|
||||
|
||||
VERSION="3.1.0"
|
||||
DATE="Nov/2022"
|
||||
TOMBEXEC="$0"
|
||||
TMPDIR="${TMP:-/tmp}"
|
||||
TOMBTMPFILES=""
|
||||
PATH="${PATH}:.:/usr/local/bin"
|
||||
exitcode=0
|
||||
# }}}
|
||||
|
||||
# {{{ Logging functions
|
||||
|
||||
_success() {
|
||||
echo "[*] " "$1" "$2" "$3" "$4" 1>&2
|
||||
}
|
||||
_message() {
|
||||
echo " . " "$1" "$2" "$3" "$4" 1>&2
|
||||
}
|
||||
_warning() {
|
||||
echo "[W] " "$1" "$2" "$3" "$4" 1>&2
|
||||
}
|
||||
_verbose() {
|
||||
echo "[D] " "$1" "$2" "$3" "$4" 1>&2
|
||||
}
|
||||
_error() {
|
||||
echo "[!] " "$1" "$2" "$3" "$4" 1>&2
|
||||
exitcode=1
|
||||
}
|
||||
_failure() {
|
||||
echo "[!!] " "$1" "$2" "$3" "$4" 1>&2
|
||||
exitcode=1
|
||||
exit 1
|
||||
}
|
||||
|
||||
# }}}
|
||||
|
||||
_success "Starting Tomb v$VERSION"
|
||||
|
||||
# {{{ Internal functions
|
||||
|
||||
_random_string() {
|
||||
len=${1:-32}
|
||||
[ "$1" != "" ] && {
|
||||
echo "print(O.random($len):base58())" | zenroom 2>/dev/null
|
||||
}
|
||||
return $?
|
||||
}
|
||||
|
||||
_tmp_create() {
|
||||
[ -d "$TMPDIR" ] || {
|
||||
# we create the tempdir with the sticky bit on
|
||||
mkdir -m 1777 "$TMPDIR"
|
||||
[ $? = 0 ] || {
|
||||
_failure "Fatal error creating the temporary directory: %s" "$TMPDIR"
|
||||
}
|
||||
}
|
||||
tfile="${TMPDIR}/`_random_string 64`" # Temporary file
|
||||
umask 066
|
||||
[ $? = 0 ] || {
|
||||
_failure "Fatal error setting the permission umask for temporary files"
|
||||
}
|
||||
[ -r "$tfile" ] && {
|
||||
_failure "Someone is messing up with us trying to hijack temporary files."
|
||||
}
|
||||
touch "$tfile"
|
||||
[ $? = 0 ] || {
|
||||
_failure "Fatal error creating a temporary file: %s" "$tfile"
|
||||
}
|
||||
_verbose "Created tempfile: ::1 temp file::" "$tfile"
|
||||
TOMBTMP="$tfile"
|
||||
TOMBTMPFILES="$TOMBTMPFILES:$tfile"
|
||||
return 0
|
||||
}
|
||||
|
||||
# }}}
|
||||
|
||||
# {{{ FreeBSD
|
||||
freebsd_mount() {
|
||||
file="$1"
|
||||
mnt="$2"
|
||||
_verbose `veracrypt -l "$file"`
|
||||
loop=`veracrypt -l "$file" | awk '{print $3}'`
|
||||
_verbose "fsck $loop"
|
||||
fsck.ext4 -p -C0 "$loop"
|
||||
lklfuse -o type=ext4 "${loop}" "$mnt"
|
||||
return $?
|
||||
}
|
||||
|
||||
freebsd_close() {
|
||||
file="$1"
|
||||
md=`veracrypt -l "$file" | awk '{print $3}'`
|
||||
# umount "$mnt"
|
||||
_verbose "md: $md"
|
||||
mnt=`pgrep -lf "lklfuse.*$md" | awk '{print $6}'`
|
||||
_verbose "mnt: $mnt"
|
||||
lkl=`pgrep -f "lklfuse.*$md" | awk '{print $1}'`
|
||||
_verbose "kill $lkl (lklfuse on $md)"
|
||||
# trying to deail with lklfuse bug
|
||||
# https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=239831
|
||||
renice -20 $lkl
|
||||
kill $lkl
|
||||
sync
|
||||
sleep 1
|
||||
kill -9 $lkl
|
||||
# lkl should have really exited now
|
||||
_verbose "veracrypt -d $file"
|
||||
veracrypt --text --non-interactive -d "$file"
|
||||
return $?
|
||||
}
|
||||
# }}}
|
||||
|
||||
# {{{ Linux
|
||||
# usage: _mount /tmp/.veracrypt_ mountpoint
|
||||
linux_mount() {
|
||||
file="$1"
|
||||
mnt="$2"
|
||||
veralist=`veracrypt -l "$file" | awk '{print($2,":",$3,":",$4)}'`
|
||||
[ "$veralist" = "" ] && {
|
||||
_error "Cannot mount tomb not yet mapped " "$file"
|
||||
return 1
|
||||
}
|
||||
loop=`echo $veralist | cut -d: -f2 | xargs`
|
||||
[ "`echo $veralist | cut -d: -f3 | xargs`" != "-" ] && {
|
||||
_error "Tomb already mounted " "$file on $loop"
|
||||
return 1
|
||||
}
|
||||
_verbose "fsck $loop"
|
||||
fsck.ext4 -p -C0 "$loop" 1>&2
|
||||
_verbose "linux_mount $mnt"
|
||||
mount "$loop" "$mnt"
|
||||
return $?
|
||||
}
|
||||
# }}}
|
||||
|
||||
# {{{ POSIX portable
|
||||
|
||||
# usage: echo PASSWORD | posix_create file size pim
|
||||
posix_create() {
|
||||
file="$1" # must not exist
|
||||
size="$2" # size in bytes
|
||||
pim="$3" # any number
|
||||
_verbose "posix_create $file $size $pim"
|
||||
veracrypt --text --non-interactive --stdin \
|
||||
-m nokernelcrypto \
|
||||
-c "$file" --volume-type normal \
|
||||
--hash sha512 --encryption serpent-aes \
|
||||
--filesystem none --size "${size}" --pim "$pim" \
|
||||
--random-source /dev/urandom -k ''
|
||||
return $?
|
||||
}
|
||||
|
||||
posix_format() {
|
||||
file="$1"
|
||||
loop=`veracrypt -l "$file" | awk '{print $3}'`
|
||||
_verbose "posix_format: ${loop}"
|
||||
mkfs.ext4 -L "`basename $file`" "$loop" # -E root_owner="${user_uid}:${user_gid}" "$loop"
|
||||
return $?
|
||||
}
|
||||
|
||||
# usage: echo PASSWORD | posix_map file pim
|
||||
posix_map() {
|
||||
file="$1"
|
||||
pim="$2"
|
||||
_verbose "posix_map $file $pim"
|
||||
veracrypt --text --non-interactive --stdin \
|
||||
--protect-hidden no -m nokernelcrypto \
|
||||
-k '' --pim "$pim" --filesystem none \
|
||||
"$file"
|
||||
return $?
|
||||
}
|
||||
|
||||
posix_close() {
|
||||
file="$1"
|
||||
_verbose "posix_close $file"
|
||||
veracrypt --text --non-interactive -d "$file"
|
||||
return $?
|
||||
}
|
||||
# }}}
|
||||
|
||||
# {{{ Initialization
|
||||
|
||||
system="unknown"
|
||||
create=""
|
||||
format=""
|
||||
map=""
|
||||
mount=""
|
||||
close=""
|
||||
|
||||
tomb_init() {
|
||||
system="`uname -s`"
|
||||
case "$system" in
|
||||
FreeBSD)
|
||||
cat <<EOF
|
||||
create=posix_create
|
||||
format=posix_format
|
||||
map=posix_map
|
||||
mount=freebsd_mount
|
||||
close=freebsd_close
|
||||
EOF
|
||||
;;
|
||||
Linux)
|
||||
cat <<EOF
|
||||
create=posix_create
|
||||
format=posix_format
|
||||
map=posix_map
|
||||
mount=linux_mount
|
||||
close=posix_close
|
||||
EOF
|
||||
;;
|
||||
*)
|
||||
_failure "Unsupported system: %s" "$system"
|
||||
esac
|
||||
echo "system=$system"
|
||||
# _verbose "system detected: %s" $system
|
||||
}
|
||||
|
||||
# }}}
|
||||
|
||||
|
||||
# {{{ Main
|
||||
[ "$1" = "source" ] && return 0
|
||||
eval "`tomb_init`"
|
||||
tombfile=""
|
||||
tombsize=""
|
||||
PIM=69
|
||||
|
||||
cmd="$1"
|
||||
shift 1
|
||||
|
||||
case "$cmd" in
|
||||
dig)
|
||||
args=2
|
||||
while [ $args -gt 0 ]; do
|
||||
[ "$1" = '-s' ] && { tombsize="$2"; shift 2; }
|
||||
[ "$1" != "" ] && { tombfile="$1"; shift 1; }
|
||||
args=$(( $args - 1 ))
|
||||
done
|
||||
|
||||
[ "$tombfile" = "" ] && _failure "Missing path to tomb"
|
||||
[ "$tombsize" = "" ] && _failure "Size argument missing, use -s"
|
||||
# TODO: check if size is integer
|
||||
# [ "$tombsize" -ge 10 ] || _failure "Tombs can't be smaller than 10 mebibytes"
|
||||
[ -e "$tombfile" ] && {
|
||||
_error "A tomb exists already. I'm not digging here:"
|
||||
ls -l "$tombfile"; exit 1
|
||||
}
|
||||
_message "Commanded to dig tomb " "$tombfile" " sized $tombsize MiB"
|
||||
touch "$tombfile" || _failure "Error creating the tomb " "$tombfile"
|
||||
# dd if=/dev/urandom bs=1048576 count=$tombsize of="$tombfile" || {
|
||||
# _failure "Error creating the tomb " "$tombfile"
|
||||
# exit 1
|
||||
# }
|
||||
bytesize="$(( $tombsize * 1048576 ))"
|
||||
[ "$bytesize" = "" ] &&
|
||||
_failure "Error reading tomb size " "$tombsize"
|
||||
if [ "$system" = "Linux" ]; then
|
||||
fallocate -x -l "$bytesize" "$tombfile" ||
|
||||
_failure "Error creating the tomb " "$tombfile"
|
||||
else
|
||||
dd if=/dev/zero of="$tombfile" count="$tombsize" bs=1048576 ||
|
||||
_failure "Error creating the tomb " "$tombfile of $tombsize MiB"
|
||||
fi
|
||||
;;
|
||||
|
||||
forge)
|
||||
args=1
|
||||
[ "$1" = "" ] && _failure "Missing argument in command " "forge"
|
||||
while [ $args -gt 0 ]; do
|
||||
case "$1" in
|
||||
'-k') tombkey="$2"; shift 2 ;;
|
||||
*) tombkey="$1"; shift 1 ;;
|
||||
esac
|
||||
args=$(( $args - 1 ))
|
||||
done
|
||||
[ "$tombkey" = "" ] && _failure "Missing path to tomb key"
|
||||
[ -e "$tombkey" ] && {
|
||||
_error "A tomb key exists already. I'm not forging here:"
|
||||
ls -l "$tombkey"; exit 1
|
||||
}
|
||||
_message "Commanded to forge tomb key " "$tombkey"
|
||||
touch "$tombkey" || _failure "Error creating the tomb key " "$tombkey"
|
||||
cat <<EOF | zenroom -z | cut -d\" -f4 > "$tombkey"
|
||||
rule check version 2.0.0
|
||||
Given nothing
|
||||
When I create the random object of '64' bytes
|
||||
Then print the 'random object' as 'hex'
|
||||
EOF
|
||||
;;
|
||||
|
||||
lock)
|
||||
args=2
|
||||
while [ $args -gt 0 ]; do
|
||||
case "$1" in
|
||||
'-k') tombkey="$2"; shift 2 ;;
|
||||
*) tombfile="$1"; shift 1 ;;
|
||||
esac
|
||||
args=$(( $args - 1 ))
|
||||
done
|
||||
case "$system" in
|
||||
Linux)
|
||||
bytesize=`stat "$tombfile" | awk '/Size:/ {print $2; exit}'`
|
||||
;;
|
||||
*)
|
||||
bytesize=`stat -f '%z' "$tombfile"`
|
||||
;;
|
||||
esac
|
||||
_message "Commanded to lock tomb " "$tombfile with key $tombkey"
|
||||
[ "$tombfile" = "" ] && _failure "Missing path to tomb"
|
||||
[ -r "$tombfile" ] || _failure "Tomb file not readable"
|
||||
[ "$tombkey" = "" ] && _failure "Missing path to key"
|
||||
[ -r "$tombkey" ] || _failure "Key file not readable"
|
||||
"$create" "$tombfile" "$bytesize" "$PIM" < "$tombkey" || {
|
||||
_failure "Error creating the tomb " "$tombfile"
|
||||
exit 1
|
||||
}
|
||||
"$map" "$tombfile" "$PIM" < "$tombkey" ||
|
||||
_failure "Error mapping the tomb " "$tombfile with key $tombkey"
|
||||
"$format" "$tombfile" ||
|
||||
_error "Error formatting tomb " "$tombfile"
|
||||
"$close" "$tombfile"
|
||||
[ $exitcode = 0 ] &&
|
||||
_success "Success locking tomb " "$tombfile with key $tombkey"
|
||||
;;
|
||||
|
||||
open)
|
||||
args=3
|
||||
while [ $args -gt 0 ]; do
|
||||
case "$1" in
|
||||
'-k') tombkey="$2"; shift 2 ;;
|
||||
*) if [ "$tombfile" = "" ]; then
|
||||
tombfile="$1"
|
||||
else
|
||||
tombmount="$1"
|
||||
fi
|
||||
shift 1 ;;
|
||||
esac
|
||||
args=$(( $args - 1 ))
|
||||
done
|
||||
_message "Commanded to open tomb " "$tombfile with key $tombkey on $tombmount"
|
||||
[ "$tombfile" = "" ] && _failure "Missing path to tomb"
|
||||
[ -r "$tombfile" ] || _failure "Tomb file not readable"
|
||||
[ "$tombkey" = "" ] && _failure "Missing path to key"
|
||||
[ -r "$tombkey" ] || _failure "Key file not readable"
|
||||
[ "$tombmount" = "" ] && tombmount="`basename $tombfile`"
|
||||
"$map" "$tombfile" "$PIM" < "$tombkey"
|
||||
[ $? != 0 ] &&
|
||||
_failure "Error mapping the tomb " "$tombfile with key $tombkey"
|
||||
"$mount" "$tombfile" "$tombmount" || {
|
||||
"$close" "$tombfile"
|
||||
_failure "Error mounting the tomb " "$tombfile on $tombmount"
|
||||
}
|
||||
;;
|
||||
|
||||
close)
|
||||
# args=1
|
||||
if [ "$1" = "all" ]; then
|
||||
"$close"
|
||||
elif [ -e "$1" ]; then
|
||||
"$close" "`realpath $1`" ||
|
||||
_failure "Error closing " "$1"
|
||||
elif [ "$1" = "" ]; then
|
||||
_failure "Missing argument: tomb file or mountpoint"
|
||||
else
|
||||
_failure "Wrong argument: $1"
|
||||
fi
|
||||
;;
|
||||
list)
|
||||
veracrypt -l
|
||||
;;
|
||||
esac
|
||||
# }}}
|
||||
|
||||
exit 0
|
@ -3,3 +3,9 @@ Build with 'qmake' and then 'make'
|
||||
|
||||
Requires QT version 5.4 or above
|
||||
|
||||
To install copy the binary in your PATH
|
||||
then all contents of pixmaps to /usr/share/pixmaps
|
||||
and all contents of i18n to /usr/share/i18n
|
||||
|
||||
The prefix /usr/local may be preferred if ever packaged.
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user