mirror of
https://github.com/Llewellynvdm/Tomb.git
synced 2024-11-12 07:46:28 +00:00
Compare commits
431 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 | ||
|
e45c005c88 | ||
|
0af46fe3c1 | ||
|
bd3e3c7056 | ||
|
ace80c87db | ||
|
2b8eec6ba5 | ||
|
7b06be5d43 | ||
|
95f2f68654 | ||
|
b34584b61c | ||
|
91e607efb5 | ||
|
ec31d2d280 | ||
|
eec64f4f65 | ||
|
a6d252c949 | ||
|
5ce9960207 | ||
|
f1f23c417b | ||
|
b054a83ee5 | ||
|
2dfb744a34 | ||
|
522ad3abad | ||
|
a0c74985ca | ||
|
59408b373f | ||
|
f2eb1fd242 | ||
|
9299f3eecf | ||
|
12767764fb | ||
|
46286047f6 | ||
|
1b535f920b | ||
|
477ab20443 | ||
|
a14a39ae12 | ||
|
1ba3c55241 | ||
|
629841c0e7 | ||
|
2f3826d88d | ||
|
aaa4637ed0 | ||
|
cdd3c5804a | ||
|
e8919af867 | ||
|
27fd026cd5 | ||
|
a27f15aada | ||
|
c293aa7261 | ||
|
24fee7a076 | ||
|
7c8067fef3 | ||
|
18b7541a98 | ||
|
b49a36a07b | ||
|
8d698ad46a | ||
|
f290904f71 | ||
|
68a9589925 | ||
|
3cb8ebefd3 | ||
|
35cf8572bf | ||
|
a66224d549 | ||
|
510c8f6430 | ||
|
5c419b3117 | ||
|
257e5ee99a | ||
|
bce58cae3e | ||
|
3440a32839 | ||
|
f5ceddc0b7 | ||
|
f4913e0744 | ||
|
66ade86441 | ||
|
d0805084a2 | ||
|
f42a4c2a0b | ||
|
08ca0a8eef | ||
|
5e3b0dec84 | ||
|
e15c58dfd7 | ||
|
61fdab85be | ||
|
74689ea484 | ||
|
7951645db5 | ||
|
70abf31bab | ||
|
ae78659efb | ||
|
ab3044c6f5 | ||
|
214ec8ecbd | ||
|
cec0c01b3e | ||
|
c7dc379c0d | ||
|
b20daeea6f | ||
|
bc963cd1ae | ||
|
3b1759b2b3 | ||
|
c8616787f7 | ||
|
31a78de23f | ||
|
60b72ad91f | ||
|
cf93551efa | ||
|
9b1d1891cc | ||
|
b72d67618b | ||
|
3f107f9d31 | ||
|
3593721967 | ||
|
09ff889c1d | ||
|
742b097192 | ||
|
a7190eb2e2 | ||
|
e083ce7a23 | ||
|
c537676e92 | ||
|
f6457090af | ||
|
121a64bc80 | ||
|
8e33be0472 | ||
|
85ac179cc8 | ||
|
21347f3657 | ||
|
6182a56fb6 | ||
|
c8be1c22dd | ||
|
6696f0c758 | ||
|
fa1049e8f0 | ||
|
aba4f4c3b8 | ||
|
8d2cb2d852 | ||
|
64daf70229 | ||
|
6926583d79 | ||
|
04ec0189a6 | ||
|
fb5eee002b | ||
|
127a8ed7ee | ||
|
056d0174f4 | ||
|
5f71b486df | ||
|
67004392fa | ||
|
c658d33187 | ||
|
9fa55d1165 | ||
|
99855746b3 | ||
|
593747d619 | ||
|
4688820b68 | ||
|
92a670efd8 | ||
|
045c55436f | ||
|
8aaa8e1725 | ||
|
408977a351 | ||
|
a609b855c7 | ||
|
36f5ed8729 | ||
|
eb57899162 | ||
|
166bbdc18c | ||
|
e99a0350fb | ||
|
bdebb6af32 | ||
|
e558ad9f13 | ||
|
1a2fd5901f | ||
|
c858def9c4 | ||
|
18067a1c2e | ||
|
7241eb0fd1 | ||
|
f9dc9ed5a7 | ||
|
5de9cb32b9 | ||
|
66aa7fdac7 | ||
|
3e0dd1e111 | ||
|
3ffcc74e5b | ||
|
1050d43c59 | ||
|
c303513be4 | ||
|
d720e4b2ce | ||
|
6c2077fee1 | ||
|
ba9c0481cc | ||
|
bb77de0815 | ||
|
29a177aa05 | ||
|
69f52bee25 | ||
|
c793e0b132 | ||
|
6352a1d417 | ||
|
0644ebe951 | ||
|
b0815b514b | ||
|
3f06bce8eb | ||
|
e37982d114 | ||
|
bea7fe3f7c | ||
|
1f022d10f1 | ||
|
2bc7e43198 | ||
|
70334f58fb | ||
|
f4f8c4e024 | ||
|
f4cdc1a0c5 | ||
|
4a7019715f | ||
|
c63fcf2730 | ||
|
528140738a | ||
|
8832471170 | ||
|
e69795fe71 | ||
|
5b7f875f3d | ||
|
b2ee2114cf | ||
|
bfe5bb9707 | ||
|
f27130053d | ||
|
6cfffef137 | ||
|
dfc593f9d6 | ||
|
e8384ec7ac | ||
|
6f89dbd2fe | ||
|
15164f5578 | ||
|
53b7460274 | ||
|
a200448de2 | ||
|
47ddeebbc4 | ||
|
5a35ab9668 | ||
|
8f8dc0a0d4 | ||
|
b23e9aa028 | ||
|
e2fe8e508e | ||
|
d1b016b3c1 | ||
|
2d516cbaed | ||
|
902860fd9f | ||
|
db7109da4a | ||
|
f72534790a | ||
|
e78af47c56 | ||
|
6c0d89cab1 | ||
|
9ee0a1550e | ||
|
537bb6aaeb | ||
|
1f852908ae | ||
|
9110ccd9d1 | ||
|
7a98ee8ba6 | ||
|
4439a6a327 | ||
|
e7e21243db | ||
|
26e549292f | ||
|
5e8db49701 | ||
|
a808d4aef8 | ||
|
42ae73d727 | ||
|
ed37b4e1fa | ||
|
fa145074f8 | ||
|
843b7fdfc4 | ||
|
5996beab0e | ||
|
cb699189e7 | ||
|
0fa4a07f8c | ||
|
18743c82a5 | ||
|
6f4cfd626c | ||
|
d41347fe22 | ||
|
88f5a926f0 | ||
|
7b72f07f96 | ||
|
14cba81f6e | ||
|
db976a5210 | ||
|
e59518befa | ||
|
f5375c61fe | ||
|
df75c39a58 | ||
|
4b1afb4fab | ||
|
b9f555b5fe | ||
|
844a886da1 | ||
|
7e88c5d07b | ||
|
99bb7fd067 | ||
|
101b89f0be | ||
|
fa44f46eba | ||
|
c502ef3d92 | ||
|
50719fb06f | ||
|
c80ebd6d6e | ||
|
6855127c15 | ||
|
feb35205c8 | ||
|
ff57aa3214 | ||
|
8f0b2943ce | ||
|
a08cb6e0de |
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
|
13
.travis.yml
Normal file
13
.travis.yml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
sudo: required
|
||||||
|
language: c
|
||||||
|
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- cp -v extras/test/Dockerfile .
|
||||||
|
- docker build -t dyne/tomb .
|
||||||
|
- docker run -it --privileged dyne/tomb /bin/bash -c "oracle & make test"
|
||||||
|
|
||||||
|
script:
|
||||||
|
- docker run -it --privileged dyne/tomb /bin/bash -c "make -C extras/kdf-keys test"
|
41
AUTHORS.md
41
AUTHORS.md
@ -1,32 +1,43 @@
|
|||||||
Cryptsetup is written by Christophe Saout and Clemens Fruhwirth.
|
Cryptsetup was originally written in 2004 by Jana Saout
|
||||||
|
|
||||||
Tomb is written and directed by Denis Roio <jaromil@dyne.org>
|
LUKS extensions are written in 2006 by Clemens Fruhwirth
|
||||||
|
|
||||||
|
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,
|
Tomb includes code and advices by Anathema, Boyska, Hellekin O. Wolf,
|
||||||
GDrooid, Parazyd.
|
Daniel Rodriguez, Parazyd, Alexandre Pujol, AitorATuin, Narrat, Artur
|
||||||
|
Malimonov and Chris Vogel.
|
||||||
|
|
||||||
The minimal Zenity GUI is being 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.
|
The Qt5 desktop tray GUI is written by Gianluca Montecchi.
|
||||||
|
|
||||||
Python Tomb wrappers are written by Reiven and Boyska.
|
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.
|
Artwork is contributed by Jordi aka Mon Mort and Logan VanCuren.
|
||||||
|
|
||||||
Gettext internationalization and Spanish translation is contributed by
|
Gettext internationalization and Spanish translation is contributed by
|
||||||
GDrooid, French translation by Hellekin, Russian translation by fsLeg,
|
Daniel Rodriguez and Francisco Serrador. French translation by
|
||||||
German translation by x3nu, Italian translation by Massimiliano
|
Hellekin and Roy Lockhart, Russian translation by fsLeg and AHOHNMYC,
|
||||||
Augello and Swedish translation by PLJ / Kosovoper.
|
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,
|
Testing, reviews and documentation contributed by Dreamer, Vlax,
|
||||||
Shining the Translucent, Mancausoft, Asbesto Molesto, Nignux, TheJH,
|
Shining the Translucent, Mancausoft, Asbesto Molesto, Nignux, TheJH,
|
||||||
The Grugq, Reiven, GDrooid, Alphazo, Brian May, fsLeg, JoelMon,
|
The Grugq, Reiven, GDrooid, Alphazo, Brian May, fsLeg, Narrat, Jerry
|
||||||
Narrat, x3nu, Jim Turner, Maxime Arthaud and the Linux Action Show!
|
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
|
Tomb includes an implementation of the "Password-Based Key Derivation
|
||||||
Function v2" based on GCrypt and written by Anthony Thyssen.
|
Function v2" based on GCrypt and written by Anthony Thyssen, with
|
||||||
|
fixes contributed by AitorATuin.
|
||||||
|
|
||||||
Tomb developers can be contacted via GitHub issues on
|
Some of the Tomb developers can be contacted via [GitHub discussions](https://github.com/dyne/Tomb/discussions)
|
||||||
https://www.github.com/dyne/Tomb or over IRC https://irc.dyne.org
|
or over Telegram via the [Dyne.org Chat Channel](https://t.me/dyne_chat).
|
||||||
channel **#dyne** (or directly over port 9999 with SSL)
|
|
||||||
|
136
ChangeLog.md
136
ChangeLog.md
@ -1,5 +1,141 @@
|
|||||||
# Tomb ChangeLog
|
# 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
|
||||||
|
|
||||||
|
This release adds new features and provides an important fix for usage
|
||||||
|
of Tomb with cryptsetup 2.1 and future versions; it also fixes a
|
||||||
|
whitespace bug in KDF passwords, all fixes are documented in
|
||||||
|
KNOWN_BUGS. A notable new feature is the libsphinx integration for
|
||||||
|
password-authenticated key agreement (PAKE). Another feature is the
|
||||||
|
integration of cloakify to support new cloak/uncloak commands that
|
||||||
|
hide keys inside long text files. Also support for gpg sub-keys has
|
||||||
|
been added and overall gpg asymmetric key protection is improved.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.5
|
||||||
|
### January 2018
|
||||||
|
|
||||||
|
This is mostly a bugfix release, including two internal
|
||||||
|
refactorings. An important change is the re-introduction (since v2.3)
|
||||||
|
of ownership change of all files inside tombs, to facilitate single
|
||||||
|
user usage, which is now default and can be prevented using the '-p'
|
||||||
|
flag on 'open' commands. The first refactoring concerns the test
|
||||||
|
units, now using the 'sharness' framework. The other refactoring
|
||||||
|
concerns 'post-hooks' now renamed to 'exec-hooks' and launched on
|
||||||
|
'open' and 'close' commands with a defined set of arguments. Another
|
||||||
|
internal change concerns the use of 'findmnt' instead of parsing the
|
||||||
|
output of 'mount -l', which grants compatibility with more recent
|
||||||
|
versions of util-linux. A fix was made to the 'slam' command for a
|
||||||
|
better process detection and the introduction of a new 'ps' command to
|
||||||
|
just list processes using tombs. Another fix was made to support tomb
|
||||||
|
hidden filenames (starting with a dot) without any extension. Some
|
||||||
|
more minor fixes were made to messaging and translations, plus all the
|
||||||
|
documentation is updated.
|
||||||
|
|
||||||
|
|
||||||
|
## 2.4
|
||||||
|
### April 2017
|
||||||
|
|
||||||
|
This release introduces a major new feature with support for
|
||||||
|
asymmetric encryption of Tomb keys using public/private GPG key
|
||||||
|
pairs. It is now possible to protect a Tomb key using a GPG key (which
|
||||||
|
can also be password-less for automations) as well encrypt a Tomb key
|
||||||
|
for multiple recipients (list of GPG ids). Other improvements include:
|
||||||
|
a fix to the 'slam' command with better detection of running programs
|
||||||
|
using 'lsof' (new optional dependency); a fix to 'forge' key creation
|
||||||
|
to really use 512 bits long keys to really trigger usage of AES256;
|
||||||
|
correct support for opening tombs in read-only mode; update of the
|
||||||
|
Tomber python wrapper in extras. Documentation has been updated.
|
||||||
|
|
||||||
|
## 2.3
|
||||||
|
### January 2017
|
||||||
|
|
||||||
|
Fix to bug occurring when using ZSh version 5.3 or higher. Fix to
|
||||||
|
inclusion of final newline in keys generated with 2.2, only affecting
|
||||||
|
third-party software. Removed chmod/chown of tombs when open. Enhanced
|
||||||
|
continuous integration script with regression tests with usage of old
|
||||||
|
stable versions of Tomb and shellcheck linting. Improved parser and
|
||||||
|
post-hooks to avoid usage of external binaries (grep and cat) also
|
||||||
|
improving security when decrypting keys. Fix for clean execution via
|
||||||
|
sudo nopasswd. Updated extras/gtomb to latest stable version. Various
|
||||||
|
documentation updates about kdf, using images as keys, deniability and
|
||||||
|
gpg-agent usage. New experimental port to Android platforms in extras.
|
||||||
|
|
||||||
## 2.2
|
## 2.2
|
||||||
### December 2015
|
### December 2015
|
||||||
|
|
||||||
|
73
INSTALL.md
73
INSTALL.md
@ -5,6 +5,7 @@
|
|||||||
Tomb needs a few programs to be installed on a system in order to work:
|
Tomb needs a few programs to be installed on a system in order to work:
|
||||||
|
|
||||||
* zsh
|
* zsh
|
||||||
|
* file
|
||||||
* sudo
|
* sudo
|
||||||
* gnupg
|
* gnupg
|
||||||
* cryptsetup
|
* cryptsetup
|
||||||
@ -20,12 +21,12 @@ To install Tomb simply download the source distribution (the tar.gz file)
|
|||||||
from https://files.dyne.org/tomb and decompress it. From a terminal:
|
from https://files.dyne.org/tomb and decompress it. From a terminal:
|
||||||
|
|
||||||
cd Downloads
|
cd Downloads
|
||||||
tar xvfz Tomb-2.0.1.tar.gz (correct with actual file name)
|
tar xvfz Tomb-2.4.tar.gz (correct with actual file name)
|
||||||
|
|
||||||
Then enter its directory and run 'make install' as root, this will install
|
Then enter its directory and run 'make install' as root, this will install
|
||||||
Tomb into /usr/local:
|
Tomb into /usr/local:
|
||||||
|
|
||||||
cd Tomb-2.0.1 (correct with actual directory name)
|
cd Tomb-2.4 (correct with actual directory name)
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
After installation one can read the commandline help or read the manual:
|
After installation one can read the commandline help or read the manual:
|
||||||
@ -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 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)
|
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
|
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.
|
into a block of text that can be used with `-k` just as a normal key.
|
||||||
|
|
||||||
@ -60,47 +61,19 @@ There are some more things that tomb can do for you, make sure you
|
|||||||
have a look at the manpage and at the commandline help to find out
|
have a look at the manpage and at the commandline help to find out
|
||||||
more.
|
more.
|
||||||
|
|
||||||
## Basic usage notes
|
# Optional tools
|
||||||
|
|
||||||
Here we collect notes on common issues users may or may not experience
|
|
||||||
and the commonly working solutions found.
|
|
||||||
|
|
||||||
### Pinentry issues
|
|
||||||
|
|
||||||
If pinentry has problems dealing with the password because of language
|
|
||||||
or tty settings on your system, try running `gpg-agent` by launching it
|
|
||||||
from the session initialization (~/.xsession or ~/.xinitrc) with this
|
|
||||||
command:
|
|
||||||
```
|
|
||||||
eval $(gpg-agent --daemon --write-env-file "${HOME}/.gpg-agent-info")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Deleting history
|
|
||||||
|
|
||||||
To improve deniability one has to avoid that tomb commands are
|
|
||||||
recorded in the shell history. In order to do so the
|
|
||||||
`HISTIGNORESPACE=1` environment setting of Zsh comes handy. Anywhere
|
|
||||||
in the `.zshrc` put:
|
|
||||||
```
|
|
||||||
export HISTIGNORESPACE=1
|
|
||||||
alias tomb=' tomb'
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# Advanced usage
|
|
||||||
|
|
||||||
## Install optional tools
|
|
||||||
|
|
||||||
Tomb can use some optional tools to extend its functionalities:
|
Tomb can use some optional tools to extend its functionalities:
|
||||||
|
|
||||||
executable | function
|
executable | function
|
||||||
---------- | ---------------------------------------------------
|
---------- | ---------------------------------------------------
|
||||||
|
lsof | slam a tomb (close even if open programs)
|
||||||
dcfldd | show progress while digging tombs and keys
|
dcfldd | show progress while digging tombs and keys
|
||||||
steghide | bury and exhume keys inside images
|
steghide | bury and exhume keys inside images
|
||||||
resizefs | extend the size of existing tomb volumes
|
resizefs | extend the size of existing tomb volumes
|
||||||
qrencode | engrave keys into printable qrcode sheets
|
qrencode | engrave keys into printable qrcode sheets
|
||||||
mlocate | fast search of file names inside tombs
|
plocate | fast search of file names inside tombs
|
||||||
swish++ | fast search of file contents inside tombs
|
recoll | fast search of file contents inside tombs
|
||||||
unoconv | fast search of contents in PDF and DOC files
|
unoconv | fast search of contents in PDF and DOC files
|
||||||
lesspipe | fast search of contents in compressed archives
|
lesspipe | fast search of contents in compressed archives
|
||||||
haveged | fast entropy generation for key forging
|
haveged | fast entropy generation for key forging
|
||||||
@ -110,12 +83,12 @@ the packages provided by each distribution.
|
|||||||
|
|
||||||
Once any of the above is installed Tomb will find the tool automatically.
|
Once any of the above is installed Tomb will find the tool automatically.
|
||||||
|
|
||||||
## Install Tomb Extras
|
# Extras
|
||||||
|
|
||||||
Tomb comes with a bunch of extra tools that contribute to enhance its
|
Tomb comes with a bunch of extra tools that contribute to enhance its
|
||||||
functionality or integrate it into particular system environments.
|
functionality or integrate it into particular system environments.
|
||||||
|
|
||||||
### extras/gtk-tray
|
## extras/gtk-tray
|
||||||
|
|
||||||
The Gtk tray adds a nifty tomb skull into the desktop toolbar: one can
|
The Gtk tray adds a nifty tomb skull into the desktop toolbar: one can
|
||||||
use it to close, slam and explore the open tomb represented by it.
|
use it to close, slam and explore the open tomb represented by it.
|
||||||
@ -130,15 +103,15 @@ To have it change directory `extras/gtk-tray` then
|
|||||||
3. run `sudo make install` (default PREFIX is `/usr/local`)
|
3. run `sudo make install` (default PREFIX is `/usr/local`)
|
||||||
4. start `tomb-gtk-tray tombname` after the tomb is open
|
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
|
## extras/qt-tray
|
||||||
|
|
||||||
The QT tray adds a tomb tray in a QT desktop toolbar. It requires at
|
The QT tray adds a tomb tray in a QT desktop toolbar. It requires at
|
||||||
least QT libraries of version 5.4 or above.
|
least QT libraries of version 5.4 or above.
|
||||||
Build with 'qmake' and then 'make'.
|
Build with 'qmake' and then 'make'.
|
||||||
|
|
||||||
### extras/kdf-keys
|
## extras/kdf-keys
|
||||||
|
|
||||||
The KDF wrapper programs allows one to use KDF rounds on passwords in
|
The KDF wrapper programs allows one to use KDF rounds on passwords in
|
||||||
order to obstruct dictionary based and similar brute-forcing attacks.
|
order to obstruct dictionary based and similar brute-forcing attacks.
|
||||||
@ -165,7 +138,7 @@ Please note that it doesn't makes much sense to use KDF keys and
|
|||||||
steganography, since the latter will invalidate the brute-forcing
|
steganography, since the latter will invalidate the brute-forcing
|
||||||
protection. For details on the issue see [KNOWN_BUGS.md](KNOWN_BUGS).
|
protection. For details on the issue see [KNOWN_BUGS.md](KNOWN_BUGS).
|
||||||
|
|
||||||
### extras/translations/
|
## extras/translations/
|
||||||
|
|
||||||
There are translations available for Tomb and they are installed by
|
There are translations available for Tomb and they are installed by
|
||||||
default. If you wish to update them manually navigate to extras/po
|
default. If you wish to update them manually navigate to extras/po
|
||||||
@ -174,7 +147,7 @@ and run 'make install' as root:
|
|||||||
cd extras/translations
|
cd extras/translations
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
### extras/gtomb/
|
## extras/gtomb/
|
||||||
|
|
||||||
This is a minimalistic graphical user interface scripted in ZSh
|
This is a minimalistic graphical user interface scripted in ZSh
|
||||||
depending from Zenity to display dialog boxes. It covers all basic
|
depending from Zenity to display dialog boxes. It covers all basic
|
||||||
@ -204,6 +177,14 @@ other people logged on the same system can easily log your passwords
|
|||||||
while such commands are executing.
|
while such commands are executing.
|
||||||
We only recommend using the pinentry to input your passwords.
|
We only recommend using the pinentry to input your passwords.
|
||||||
|
|
||||||
|
At the time of writing another free software graphical application
|
||||||
|
supports opening and closing Tombs via a plugin installed by
|
||||||
|
default: [zuluCrypt](https://mhogomchungu.github.io/zuluCrypt/). One
|
||||||
|
needs to activate the Tomb plugin included in the zuluCrypt source to
|
||||||
|
be able to create, open and close tombs. Beware zuluCrypt may miss
|
||||||
|
advanced Tomb functionalities that are only available from the
|
||||||
|
command-line.
|
||||||
|
|
||||||
## Python
|
## Python
|
||||||
|
|
||||||
![](extras/images/python_for_tomb.png)
|
![](extras/images/python_for_tomb.png)
|
||||||
@ -212,14 +193,6 @@ A Python wrapper is under development and already usable, but it
|
|||||||
introduces some vulnerabilities mentioned above. Find it in
|
introduces some vulnerabilities mentioned above. Find it in
|
||||||
`extras/tomber`. For more information see [PYTHON](extras/PYTHON.md).
|
`extras/tomber`. For more information see [PYTHON](extras/PYTHON.md).
|
||||||
|
|
||||||
## Graphical applications
|
|
||||||
|
|
||||||
So far the only graphical application supporting Tomb volumes is
|
|
||||||
[ZuluCrypt](https://github.com/mhogomchungu/zuluCrypt). One needs to
|
|
||||||
activate the Tomb plugin included in its source and will be able to
|
|
||||||
create, open and close tombs. It might still miss advanced Tomb
|
|
||||||
functionalities that are only available from the command-line.
|
|
||||||
|
|
||||||
## Let us know!
|
## Let us know!
|
||||||
|
|
||||||
If you plan to develop any kind of wrapper for Tomb you are welcome to
|
If you plan to develop any kind of wrapper for Tomb you are welcome to
|
||||||
|
@ -1,3 +1,42 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
Tomb uses the cryptsetup LUKS volume header default to type luks1
|
||||||
|
which has been for long the default in cryptsetup. But starting from
|
||||||
|
cryptsetup v2.1 a new default has been introduced (luks2) and the
|
||||||
|
--type option added to specify the old luks1.
|
||||||
|
|
||||||
|
Using Tomb version 2.6 (and future releases) the problem opening tombs
|
||||||
|
using recent GNU/Linux distributions is fixed.
|
||||||
|
|
||||||
|
# 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 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 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
|
||||||
|
this bug.
|
||||||
|
|
||||||
# Vulnerability to password bruteforcing
|
# Vulnerability to password bruteforcing
|
||||||
## Issue affecting keys used in steganography
|
## Issue affecting keys used in steganography
|
||||||
|
|
||||||
@ -23,6 +62,18 @@
|
|||||||
a good practice to change it using the `setkey` command on a secure
|
a good practice to change it using the `setkey` command on a secure
|
||||||
machine, possibly while off-line or in single user mode.
|
machine, possibly while off-line or in single user mode.
|
||||||
|
|
||||||
|
# Ending newline in tomb keys
|
||||||
|
## 2.2
|
||||||
|
|
||||||
|
When used to forge new keys, Tomb version 2.2 incorrectly added a new
|
||||||
|
line ('\n', 0x0A) character at the end of each key's secret sequence
|
||||||
|
before encoding it with GnuPG. This does not affect Tomb regression
|
||||||
|
and compatibility with other Tomb versions as this final newline is
|
||||||
|
ignored in any case, but third party software may have
|
||||||
|
problems. Those writing a software that supports opening Tomb files
|
||||||
|
should always ignore the final newline when present in the secret
|
||||||
|
material obtained after decoding the key with the password.
|
||||||
|
|
||||||
# Versioning and stdin key
|
# Versioning and stdin key
|
||||||
## 1.5
|
## 1.5
|
||||||
|
|
||||||
|
13
Makefile
13
Makefile
@ -2,6 +2,14 @@ PROG = tomb
|
|||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
MANDIR ?= ${PREFIX}/share/man
|
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:
|
all:
|
||||||
@echo
|
@echo
|
||||||
@echo "Tomb is a script and does not need compilation, it can be simply executed."
|
@echo "Tomb is a script and does not need compilation, it can be simply executed."
|
||||||
@ -9,7 +17,7 @@ all:
|
|||||||
@echo "To install it in /usr/local together with its manpage use 'make install'."
|
@echo "To install it in /usr/local together with its manpage use 'make install'."
|
||||||
@echo
|
@echo
|
||||||
@echo "To run Tomb one needs to have some tools installed on the system:"
|
@echo "To run Tomb one needs to have some tools installed on the system:"
|
||||||
@echo "Sudo, cryptsetup, pinentry and gnupg. Also wipe is recommended."
|
@echo "Sudo, cryptsetup, pinentry and gnupg."
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
install:
|
install:
|
||||||
@ -24,3 +32,6 @@ install:
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
make -C extras/test
|
make -C extras/test
|
||||||
|
|
||||||
|
lint:
|
||||||
|
shellcheck -s bash -e SC1058,SC1073,SC1072,SC1009 tomb
|
||||||
|
228
README.md
228
README.md
@ -1,232 +1,58 @@
|
|||||||
..... ..
|
# Tomb: The Linux Crypto Undertaker
|
||||||
.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*%"
|
|
||||||
^"***"` "`
|
|
||||||
|
|
||||||
*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://www.dyne.org/wp-content/uploads/2015/12/software_by_dyne.png)](http://www.dyne.org)
|
Minimalistic command line tool based on Linux dm-crypt and LUKS, trusted by hackers since 2007.
|
||||||
|
|
||||||
Updates on website: https://www.dyne.org/software/tomb
|
You can keep your volumes secure and easily manageable with simple commands.
|
||||||
|
|
||||||
Get the stable .tar.gz signed release for production use!
|
|
||||||
|
|
||||||
Download it from https://files.dyne.org/tomb
|
|
||||||
|
|
||||||
![tomb's logo](https://github.com/dyne/Tomb/blob/master/extras/images/monmort.png)
|
![tomb's logo](https://github.com/dyne/Tomb/blob/master/extras/images/monmort.png)
|
||||||
|
|
||||||
# What is Tomb, the crypto undertaker?
|
Create a new 120MiB `secret.tomb` folder and lock it with a new `secret.tomb.key` file.
|
||||||
|
|
||||||
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 shared GNU/Linux components.
|
|
||||||
|
|
||||||
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:
|
|
||||||
```
|
```
|
||||||
$ tomb dig -s 100 secret.tomb
|
$ tomb dig -s 120 secret.tomb
|
||||||
$ tomb forge secret.tomb.key
|
$ tomb forge -k secret.tomb.key
|
||||||
$ tomb lock secret.tomb -k secret.tomb.key
|
$ tomb lock -k secret.tomb.key secret.tomb
|
||||||
```
|
```
|
||||||
To open it, do
|
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
|
$ 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)
|
||||||
|
|
||||||
For the instructions on how to get started using Tomb, see [INSTALL](INSTALL.md).
|
<a href="https://dyne.org/tomb"><img src="https://files.dyne.org/software_by_dyne.png" width="30%"></a>
|
||||||
|
|
||||||
```
|
More information in `man tomb` and on [dyne.org/docs/tomb](https://dyne.org/docs/tomb).
|
||||||
Syntax: tomb [options] command [arguments]
|
|
||||||
|
|
||||||
Commands:
|
### 💾 [Download from files.dyne.org/tomb](https://files.dyne.org/tomb/)
|
||||||
|
|
||||||
// Creation:
|
Use only stable and signed releases in production!
|
||||||
dig create a new empty TOMB file of size -s in MB
|
|
||||||
forge create a new KEY file and set its password
|
|
||||||
lock installs a lock on a TOMB to use it with KEY
|
|
||||||
|
|
||||||
// Operations on tombs:
|
Tomb's development is community-based!
|
||||||
open open an existing TOMB (-k specify KEY file)
|
|
||||||
index update the search indexes of tombs
|
|
||||||
search looks for filenames matching text patterns
|
|
||||||
list list of open TOMBs and information on them
|
|
||||||
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)
|
|
||||||
|
|
||||||
// Operations on keys:
|
## 🤏🏽 How can you help
|
||||||
passwd change the password of a KEY (needs old pass)
|
|
||||||
setkey change the KEY locking a TOMB (needs old key and pass)
|
|
||||||
|
|
||||||
// Backup on paper:
|
Donations are very welcome on [dyne.org/donate](https://www.dyne.org/donate)
|
||||||
engrave makes a QR code of a KEY to be saved on paper
|
|
||||||
|
|
||||||
// Steganography:
|
Translations are also welcome: see our simple [translation guide](https://github.com/dyne/Tomb/blob/master/extras/translations/README.md)
|
||||||
bury hide a KEY inside a JPEG image (for use with -k)
|
|
||||||
exhume extract a KEY from a JPEG image (prints to stout)
|
|
||||||
|
|
||||||
Options:
|
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).
|
||||||
|
|
||||||
-s size of the tomb file when creating/resizing one (in MB)
|
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.
|
||||||
-k path to the key to be used ('-k -' to read from stdin)
|
|
||||||
-n don't process the hooks found in tomb
|
|
||||||
-o mount options used to open (default: rw,noatime,nodev)
|
|
||||||
-f force operation (i.e. even if swap is active)
|
|
||||||
--kdf generate passwords armored against dictionary attacks
|
|
||||||
|
|
||||||
-h print this help
|
There is also a [space for discussion](https://github.com/dyne/Tomb/discussions) of new features, desiderata and whatnot on github.
|
||||||
-v print version, license and list of available ciphers
|
|
||||||
-q run quietly without printing informations
|
|
||||||
-D print debugging information at runtime
|
|
||||||
```
|
|
||||||
|
|
||||||
# What is this for, exactly?
|
|
||||||
|
|
||||||
This tool can be used to dig .tomb files (LUKS volumes), forge keys
|
|
||||||
protected by a password (GnuPG symmetric 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, 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: secures the
|
|
||||||
typing of passwords from keyloggers, facilitates hiding keys inside
|
|
||||||
images, indexes and search a tomb's contents, 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
|
|
||||||
```
|
|
||||||
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 to be safe for
|
|
||||||
military grade use where the integrity of information stored depends
|
|
||||||
on the user's behaviour and the strength of a standard AES-256 (XTS
|
|
||||||
plain) encryption algorithm.
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# How can you help
|
|
||||||
|
|
||||||
Donations are very welcome, please go to https://www.dyne.org/donate
|
|
||||||
|
|
||||||
Translations are also needed: they can be contributed via this website
|
|
||||||
https://poeditor.com/join/project/b276xMGAmB
|
|
||||||
or simply sending the .po file. Start from `extras/po/tomb.pot`.
|
|
||||||
|
|
||||||
The code is pretty short and readable: start looking around and the
|
|
||||||
materials found in `doc/` which are good pointers at security measures
|
|
||||||
to be further implemented.
|
|
||||||
|
|
||||||
For the bleeding edge 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)
|
|
||||||
|
|
||||||
# Licensing
|
# Licensing
|
||||||
|
|
||||||
Tomb is Copyright (C) 2007-2016 by the Dyne.org Foundation
|
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.
|
||||||
|
|
||||||
More information on all the developers involved is found in the
|
## [More info on dyne.org/tomb](https://dyne.org/tomb)
|
||||||
[AUTHORS](AUTHORS.md) file.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
@ -4,11 +4,7 @@ Style guidelines
|
|||||||
Indentation
|
Indentation
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Code must be indented using four spaces.
|
Code must be indented using hard tabs.
|
||||||
In vim, this can be accomplished using
|
|
||||||
|
|
||||||
set shiftwidth=4
|
|
||||||
set expandtab
|
|
||||||
|
|
||||||
Naming
|
Naming
|
||||||
------
|
------
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
Overview
|
Overview
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
What is a key?
|
||||||
What's a key?
|
It is a gpg symmetrically encrypted, ascii-armored file.
|
||||||
It basicly is a gpg simmetrically encrypted, ascii-armored file.
|
The encryption key is a function (see below, on KDF section) of your tomb
|
||||||
It's encryption key is a function (see below, on KDF section) of your tomb
|
|
||||||
passphrase.
|
passphrase.
|
||||||
|
|
||||||
|
|
||||||
Layout
|
Layout
|
||||||
======
|
======
|
||||||
|
|
||||||
|
@ -31,11 +31,11 @@ Linux hard disk encryption settings
|
|||||||
and LRW for standardisation. EME along with it's cousin CMC seems to
|
and LRW for standardisation. EME along with it's cousin CMC seems to
|
||||||
provide the best security level, but imposes additional encryption
|
provide the best security level, but imposes additional encryption
|
||||||
steps. Plumb-IV is discussed only for reference, because it has the
|
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.
|
weaknesses of CBC encryption.
|
||||||
|
|
||||||
As convention, this document will use the term "blocks", when it
|
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
|
and will use the term "sectors", when it refers to a 512-byte wide hard
|
||||||
disk block.
|
disk block.
|
||||||
|
|
||||||
@ -171,8 +171,8 @@ Content leaks
|
|||||||
cipher blocks. But how does this number grow in n? Obviously
|
cipher blocks. But how does this number grow in n? Obviously
|
||||||
exponentially. Plotting a few a decimal powers shows that the chance
|
exponentially. Plotting a few a decimal powers shows that the chance
|
||||||
for finding at least on identical cipher pair flips to 1 around n =
|
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
|
10^20 (n = 10^40 for a 256-bit cipher). This inflection point is reached
|
||||||
for a 146 million TB storage (or a hundered thousand trillion trillions
|
for a 146 million TB storage (or a hundred thousand trillion trillions
|
||||||
TB storage for a 256-bit cipher).
|
TB storage for a 256-bit cipher).
|
||||||
|
|
||||||
^1The blocks with available preceding cipher blocks is 62/1KB for all
|
^1The blocks with available preceding cipher blocks is 62/1KB for all
|
||||||
|
18
doc/TODO.org
18
doc/TODO.org
@ -9,8 +9,14 @@ Roadmap notes:
|
|||||||
|
|
||||||
* Release 3.0
|
* Release 3.0
|
||||||
|
|
||||||
|
*** [#A] integrate the zenroom for custom crypto functions
|
||||||
|
https://decodeproject.github.io/lua-zenroom
|
||||||
|
|
||||||
|
*** [#A] study cryptsetup 2.0 and integrate it
|
||||||
|
|
||||||
|
In particular kernel keystore functionalities
|
||||||
|
|
||||||
*** [#A] support BtrFS and snapshots
|
*** [#A] support BtrFS and snapshots
|
||||||
*** [#A] system to split passwords in parts (ssss)
|
|
||||||
*** [#B] modular encryption system support
|
*** [#B] modular encryption system support
|
||||||
|
|
||||||
to go beyond dm-crypt/cryptsetup
|
to go beyond dm-crypt/cryptsetup
|
||||||
@ -21,13 +27,21 @@ Roadmap notes:
|
|||||||
|
|
||||||
*** [#B] udev rules to avoid usb automount of keyplug in gnome
|
*** [#B] udev rules to avoid usb automount of keyplug in gnome
|
||||||
*** [#B] sign and verify tomb script integrity
|
*** [#B] sign and verify tomb script integrity
|
||||||
*** [#B] make a graphical tomb undertaker (gnome-druid in glade?)
|
|
||||||
*** [#B] analyse and show tomb entropy using libdisorder
|
*** [#B] analyse and show tomb entropy using libdisorder
|
||||||
*** [#B] use inotify on tomb
|
*** [#B] use inotify on tomb
|
||||||
inotify can also count when was the last time tomb was used and
|
inotify can also count when was the last time tomb was used and
|
||||||
unmount it automatically after a timeout, see how much free space
|
unmount it automatically after a timeout, see how much free space
|
||||||
is left and warn when the space is almost finished
|
is left and warn when the space is almost finished
|
||||||
|
|
||||||
|
*** DONE [#A] system to split passwords in parts
|
||||||
|
CLOSED: [2018-01-03 Wed 19:48]
|
||||||
|
|
||||||
|
solved with secrets.dyne.org
|
||||||
|
*** DONE [#B] make a graphical tomb undertaker (gnome-druid in glade?)
|
||||||
|
CLOSED: [2018-01-03 Wed 19:49]
|
||||||
|
|
||||||
|
solved by gtomb and qtomb
|
||||||
|
|
||||||
|
|
||||||
** Notes from #CybRes
|
** Notes from #CybRes
|
||||||
|
|
||||||
|
362
doc/tomb.1
362
doc/tomb.1
@ -1,4 +1,4 @@
|
|||||||
.TH tomb 1 "November 26, 2014" "tomb"
|
.TH tomb 1 "Jun 25, 2023" "tomb"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
Tomb \- the Crypto Undertaker
|
Tomb \- the Crypto Undertaker
|
||||||
@ -30,23 +30,27 @@ harddisk and its key file on a USB stick.
|
|||||||
.IP "dig"
|
.IP "dig"
|
||||||
Generates a file that can be used as a tomb and will occupy as much
|
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
|
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
|
then be locked using a \fIkey\fR. It takes a mandatory \fI-s\fR option
|
||||||
the size in megabytes (MiB). Tombs are digged using
|
which is the size in megabytes (MiB). Tombs are digged using random
|
||||||
low-quality random data (/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
|
.B
|
||||||
.IP "forge"
|
.IP "forge"
|
||||||
Creates a new \fIkey\fR and prompts the user for a \fIpassword\fR to
|
Creates a new \fIkey\fR and prompts the user for a \fIpassword\fR to protect
|
||||||
protect its usage. This operation requires high quality random data
|
its usage using symmetric encryption. This operation uses random data from a
|
||||||
(/dev/random) which can take quite some time to be gathered on a
|
non-blocking source (/dev/urandom) and it may take long only in some cases; to
|
||||||
server: it works better on a desktop where the mouse can be moved
|
switch using a blocking source the \fI--use-random\fR flag can be used. The
|
||||||
around for entropy. The default cipher to protect the key is AES256, a
|
\fI-g\fR option switches on the use of a GPG key instead of a password
|
||||||
custom one can be specified using the \fI-o\fR option, for a list of
|
(asymmetric encryption), then the \fI-r\fR option indicates the recipient key;
|
||||||
supported ciphers use \fI-v\fR. For additional protection against
|
more recipient GPG ids can be indicated (comma separated). The default cipher
|
||||||
dictionary attacks on keys, the (experimental) \fI--kdf\fR option can
|
to protect the key is AES256, a custom one can be specified using the \fI-o\fR
|
||||||
be used when forging a key, making sure that the \fItomb-kdb-pbkdf2\fR
|
option, for a list of supported ciphers use \fI-v\fR. For additional protection
|
||||||
binaries in \fIextras/kdf\fR were compiled and installed on the
|
against dictionary attacks on keys, the \fI--kdf\fR option can be used when
|
||||||
system.
|
forging a key, making sure that the binaries in \fIextras/kdf\fR were compiled
|
||||||
|
and installed on the system.
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "lock"
|
.IP "lock"
|
||||||
@ -54,20 +58,48 @@ Initializes and locks an empty tomb (made with \fIdig\fR) using a key
|
|||||||
(made with \fIforge\fR), making it ready for usage. After this
|
(made with \fIforge\fR), making it ready for usage. After this
|
||||||
operation, the tomb can only be opened in possession of the key and
|
operation, the tomb can only be opened in possession of the key and
|
||||||
knowing its password. As in any other command requiring a key, the
|
knowing its password. As in any other command requiring a key, the
|
||||||
option \fI-k\fR should be used to specify a key file. The \fI-o\fR
|
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
|
option can be used to specify the cipher specification: default is
|
||||||
"aes-xts-plain64:sha256", old versions of Tomb used "aes-cbc-essiv:sha256".
|
"aes-xts-plain64", old versions of Tomb used "aes-cbc-essiv:sha256".
|
||||||
This operation requires root privileges to loopback mount, format the tomb (using
|
If you are looking for something exotic, also try
|
||||||
LUKS and Ext4), then set the key in its first LUKS slot.
|
"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
|
.B
|
||||||
.IP "open"
|
.IP "open"
|
||||||
Opens an existing \fI.tomb\fR (first argument) using a key (\fI-k\fR),
|
Opens an existing \fItomb file\fR (first argument) using a key
|
||||||
if a second argument is given it will indicate the \fImountpoint\fR
|
(\fI-k\fR) which can also be hidden inside a \fIjpeg image\fR (see
|
||||||
where the tomb should be made accessible, else the tomb is mounted in
|
\fIbury\fR/\fIexhume\fR) or a long text file
|
||||||
a directory inside /media (if not available it uses /run/media/$USER).
|
(see\fIcloak\fR/\fIuncloak\fR). If a second argument is given it will
|
||||||
The option \fI-o\fR can be used to pass mount(8) options
|
indicate the \fImountpoint\fR where the tomb should be made
|
||||||
(default: rw,noatime,nodev).
|
accessible, else the tomb is mounted in a directory inside /media (if
|
||||||
|
not available it uses /run/media/$USER). The option \fI-o\fR can be
|
||||||
|
used to pass mount(8) options (default: rw,noatime,nodev). The
|
||||||
|
\fI-g\fR option is needed when using GPG encryption to recipients.
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "list"
|
.IP "list"
|
||||||
@ -78,23 +110,33 @@ returns an error if it's not found. If the option
|
|||||||
\fI--get-mountpoint\fR is used then print a simple list of currently
|
\fI--get-mountpoint\fR is used then print a simple list of currently
|
||||||
open tomb mountpoint paths.
|
open tomb mountpoint paths.
|
||||||
|
|
||||||
|
.B
|
||||||
|
.IP "ps"
|
||||||
|
List all the processes found running inside the tombs that are open,
|
||||||
|
printing out their PIDs and owners. This is useful to have an overview
|
||||||
|
of programs that are keeping the tombs busy and would eventually be
|
||||||
|
killed by the \fIslam\fR command. The lsof(8) utility is used
|
||||||
|
internally to enumerate processes running in one or all tombs.
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "index"
|
.IP "index"
|
||||||
Creates or updates the search indexes of all tombs currently open:
|
Creates or updates the search indexes of all tombs currently open:
|
||||||
enables use of the \fIsearch\fR command using simple word patterns on
|
enables use of the \fIsearch\fR command using simple word patterns on
|
||||||
file names. Indexes are created using mlocate's updatedb(8) and
|
file names. Indexes are created using plocate's updatedb(8) and
|
||||||
swish-e(1) if they are found on the system. Indexes allow to search
|
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
|
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
|
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.
|
indexing a specific tomb simply touch a \fI.noindex\fR file in it.
|
||||||
|
Useful tools to have: poppler-utils, aspell, xdg-utils, plocate.
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "search"
|
.IP "search"
|
||||||
Takes any string as argument and searches for them through all tombs
|
Takes any string as argument and searches for them through all tombs
|
||||||
currently open and previously indexed using the \fIindex\fR command.
|
currently open and previously indexed using the \fIindex\fR command.
|
||||||
The search matches filenames if mlocate is installed and then also
|
The search matches filenames if plocate is installed and then also
|
||||||
file contents if swish++ is present on the system, results are listed
|
file contents if recoll is installed, all results are listed on the
|
||||||
on the console.
|
console.
|
||||||
|
One can also run recoll's GUI using \fIrecoll -c /media/tomb\fR
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "close"
|
.IP "close"
|
||||||
@ -108,36 +150,43 @@ the tomb is in use by running processes (to force close, see
|
|||||||
.IP "slam"
|
.IP "slam"
|
||||||
Closes a tomb like the command \fIclose\fR does, but it doesn't fail
|
Closes a tomb like the command \fIclose\fR does, but it doesn't fail
|
||||||
even if the tomb is in use by other application processes: it looks
|
even if the tomb is in use by other application processes: it looks
|
||||||
for and violently kills \-9 each of them. This command may
|
for and closes each of them (in order: TERM, HUP, KILL). This command may
|
||||||
provoke unsaved data loss, but assists users to face surprise
|
provoke unsaved data loss, but assists users to face surprise
|
||||||
situations.
|
situations. It requires \fIlsof\fR else it falls back to \fIclose\fR.
|
||||||
|
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "passwd"
|
.IP "passwd"
|
||||||
Changes the password protecting a key file specified using
|
Changes the password protecting a key file specified using
|
||||||
\fI-k\fR. The user will need to know the key's current password, then
|
\fI-k\fR. With keys encrypted for GPG recipients use \fI-g\fR followed
|
||||||
its content will be decoded and reencoded using the new one. This
|
by \fI-r\fR to indicate the new recipient key, or a comma separated
|
||||||
action can't be forced if the current password is not known. If the
|
list.. The user will need to know the key's current password, or
|
||||||
key file is broken (missing headers) this function also attempts its
|
possess at least one of the current recipients GPG secret keys,
|
||||||
recovery.
|
because the key contents will be decoded and reencoded using the new
|
||||||
|
passwords or keys. If the key file is broken (missing headers) this
|
||||||
|
function also attempts its recovery.
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "setkey"
|
.IP "setkey"
|
||||||
Changes the key file that locks a tomb, substituting the old one with
|
Changes the key file that locks a tomb, substituting the old one with
|
||||||
a new one. Both the old and the new key files are needed for this
|
a new one. Both the old and the new key files are needed for this
|
||||||
operation and their passwords must be known. The new key must be
|
operation and their passwords or GPG recipient(s) secret keys must be
|
||||||
specified using the \fI-k\fR option, the first argument should be the old
|
available. The new key must be specified using the \fI-k\fR option,
|
||||||
key and the second and last argument the tomb file.
|
the first argument should be the old key and the second and last
|
||||||
|
argument the tomb file. Use the \fI-g\fR option to unlock the tomb
|
||||||
|
with a GPG key, the \fI-r\fR to indicate the recipient or a comma
|
||||||
|
separated list for more than one recipient.
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "resize"
|
.IP "resize"
|
||||||
Increase the size of a tomb file to the amount specified by the
|
Increase the size of a tomb file to the amount specified by the
|
||||||
\fI-s\fR option, which is the new size in megabytes (MiB). Full access to the tomb using
|
\fI-s\fR option, which is the new size in megabytes (MiB). Full access
|
||||||
a key (\fI-k\fR) and its password is required. Tombs can only grow and
|
to the tomb using a key (\fI-k\fR) and its password is required. Tombs
|
||||||
can never be made smaller. This command makes use of the cryptsetup
|
can only grow and can never be made smaller. This command makes use of
|
||||||
resize feature and the resize2fs command: its much more practical than
|
the cryptsetup(8) resize feature and the resize2fs command: its much
|
||||||
creating a new tomb and moving everything into it.
|
more practical than creating a new tomb and moving everything into
|
||||||
|
it. There is no data-loss if a failure occurs during resize: the
|
||||||
|
command can be re-launched and the resize operation will complete.
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "engrave"
|
.IP "engrave"
|
||||||
@ -155,7 +204,9 @@ Hides a tomb key (\fI-k\fR) inside a \fIjpeg image\fR (first argument)
|
|||||||
using \fIsteganography\fR: the image will change in a way that cannot
|
using \fIsteganography\fR: the image will change in a way that cannot
|
||||||
be noticed by human eye and hardly detected by data analysis. This
|
be noticed by human eye and hardly detected by data analysis. This
|
||||||
option is useful to backup tomb keys in unsuspected places; it depends
|
option is useful to backup tomb keys in unsuspected places; it depends
|
||||||
from the availability of \fIsteghide\fR.
|
from the availability of \fIsteghide\fR. Use the \fI-g\fR flag and
|
||||||
|
\fI-r\fR option followed by recipient id to use GPG asymmetric
|
||||||
|
encryption.
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "exhume"
|
.IP "exhume"
|
||||||
@ -166,27 +217,52 @@ containing a key. If the right key password is given, the key will be
|
|||||||
exhumed. If the password is not known, it is very hard to verify if a
|
exhumed. If the password is not known, it is very hard to verify if a
|
||||||
key is buried in any image or not.
|
key is buried in any image or not.
|
||||||
|
|
||||||
|
.B
|
||||||
|
.IP "cloak"
|
||||||
|
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"
|
||||||
|
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
|
.SH OPTIONS
|
||||||
.B
|
.B
|
||||||
.B
|
.B
|
||||||
.IP "-k \fI<keyfile>\fR"
|
.IP "-k \fI<keyfile>\fR"
|
||||||
For all operations requiring a key, this option specifies the location
|
For all operations requiring a key, this option specifies the location
|
||||||
of the key file to use. Arguments can also be \fIjpeg image\fR files
|
of the key file to use. Arguments can also be \fIjpeg image\fR files
|
||||||
where keys have been hidden using the \fIbury\fR command, or text
|
where keys have been hidden using the \fIbury\fR or \fIcloak\fR
|
||||||
files retrieved from \fIengraved\fR QR codes. If the \fIkeyfile\fR
|
commands, or text files retrieved from \fIengraved\fR QR codes. If the
|
||||||
argument is "-" (dash), Tomb will read the key from stdin (blocking).
|
\fIkeyfile\fR argument is "-" (dash), Tomb will read the key from
|
||||||
|
stdin (blocking).
|
||||||
.B
|
.B
|
||||||
.IP "-n"
|
.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.
|
See the \fIHOOKS\fR section in this manual for more information.
|
||||||
.B
|
.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 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
|
||||||
.IP "-o"
|
.IP "-o"
|
||||||
Manually specify mount options to be used when opening a tomb instead
|
Manually specify mount options to be used when opening a tomb instead
|
||||||
of the default \fIrw,noatime,nodev\fR, i.e. to mount a tomb read-only
|
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
|
(ro) to prevent any modification of its data. Can also be used to
|
||||||
change the symmetric encryption algorithm for keys during \fIforge\fR
|
change the symmetric encryption algorithm for keys during \fIforge\fR
|
||||||
operations (default \fIAES256\fR) or the LUKS encryption method during
|
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
|
.B
|
||||||
.IP "-f"
|
.IP "-f"
|
||||||
Force flag, currently used to override swap checks, might be
|
Force flag, currently used to override swap checks, might be
|
||||||
@ -197,12 +273,40 @@ what you are doing if you force an operation.
|
|||||||
When digging or resizing a tomb, this option must be used to specify
|
When digging or resizing a tomb, this option must be used to specify
|
||||||
the \fIsize\fR of the new file to be created. Units are megabytes (MiB).
|
the \fIsize\fR of the new file to be created. Units are megabytes (MiB).
|
||||||
.B
|
.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).
|
||||||
|
.B
|
||||||
|
.IP "-r \fI<gpg_id>[,<gpg_id2>]\fR"
|
||||||
|
Provide a new set of recipient(s) to encrypt a tomb key. \fIgpg_ids\fR
|
||||||
|
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"
|
.IP "--kdf \fI<itertime>\fR"
|
||||||
Activate the KDF feature against dictionary attacks when creating a
|
Activate the KDF feature against dictionary attacks when creating a key: forces
|
||||||
key: forces a delay of \fI<itertime>\fR seconds every time this key is used.
|
a delay of \fI<itertime>\fR times every time this key is used. The actual time
|
||||||
You should keep in mind that the actual iteration count is calculated based on
|
to wait depends on the CPU speed (default) or the RAM size (argon2) of the
|
||||||
the performance of the computer where you forge the key.
|
computer where the key is used. Using 5 or 10 is a sane amount for modern
|
||||||
The argument must be an integer, so you cannot say \fI--kdf 0.3\fR for 300ms.
|
computers, the value is multiplied by 1 million.
|
||||||
|
.B
|
||||||
|
.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
|
.B
|
||||||
.IP "-h"
|
.IP "-h"
|
||||||
Display a help text and quit.
|
Display a help text and quit.
|
||||||
@ -227,9 +331,10 @@ Enable using dev-mode arguments, i.e. to pass passwords from
|
|||||||
commandline options. This is mostly used needed for execution by
|
commandline options. This is mostly used needed for execution by
|
||||||
wrappers and testing suite.
|
wrappers and testing suite.
|
||||||
.B
|
.B
|
||||||
.IP "--use-urandom"
|
.IP "--use-random"
|
||||||
Use an inferior quality random source to improve the speed of key
|
Use a blocking random source. Tomb uses by default /dev/urandom since
|
||||||
generation at the cost of security (needed for the testing suite).
|
the non-blocking source of Linux kernel doesn't degrades the quality
|
||||||
|
of random.
|
||||||
.B
|
.B
|
||||||
.IP "--tomb-pwd <string>"
|
.IP "--tomb-pwd <string>"
|
||||||
Use string as password when needed on tomb.
|
Use string as password when needed on tomb.
|
||||||
@ -251,17 +356,19 @@ Switch to this TTY terminal when dropping privileges.
|
|||||||
|
|
||||||
Hooks are special files that can be placed inside the tomb and trigger
|
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
|
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.
|
base root of the tomb.
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "bind-hooks"
|
.IP "bind-hooks"
|
||||||
This hook file consists of a simple two column list of files or
|
This hook file consists of a simple text file named \fIbind-hooks\fR
|
||||||
directories inside the tomb to be made directly accessible inside the
|
containing a two column list of paths to files or directories inside
|
||||||
current user's home directory. Tomb will use the "mount \-o bind"
|
the tomb. The files and directories will be made directly
|
||||||
command to bind locations inside the tomb to locations found in $HOME
|
accessible by the tomb \fIopen\fR command inside the current user's
|
||||||
so in the first column are indicated paths relative to the tomb and in
|
home directory. Tomb uses internally the "mount \-o bind" command to
|
||||||
the second column are indicated paths relative to $HOME contents, for
|
bind locations inside the tomb to locations found in $HOME. In the
|
||||||
|
first column are indicated paths relative to the tomb and in the
|
||||||
|
second column are indicated paths relative to $HOME contents, for
|
||||||
example:
|
example:
|
||||||
.EX
|
.EX
|
||||||
mail mail
|
mail mail
|
||||||
@ -271,20 +378,21 @@ example:
|
|||||||
.EE
|
.EE
|
||||||
|
|
||||||
.B
|
.B
|
||||||
.IP "post-hooks"
|
.IP "exec-hooks"
|
||||||
This hook file gets executed as user by tomb right after opening it;
|
This hook file gets executed as user by tomb with the first argument
|
||||||
it should be a regular shell script, starting with a shebang. Tomb
|
determining the step of execution (\fIopen\fR or \fIclose\fR) and the second
|
||||||
executes this hook as user (dropping root privileges) and giving it
|
being the full path to the mountpoint. The \fIexec-hooks\fR file should be
|
||||||
two arguments: "$1" is "open" or "close" depending from the tomb
|
executable (ELF or shell script) and present inside the Tomb. Tomb
|
||||||
command given, "$2" is the full path to the mountpoint where the tomb
|
executes this hook as user and adds the name, loopback device and
|
||||||
is open.
|
dev-mapper device paths as additional arguments for the \fIclose\fR
|
||||||
|
command.
|
||||||
|
|
||||||
.SH PRIVILEGE ESCALATION
|
.SH PRIVILEGE ESCALATION
|
||||||
|
|
||||||
The tomb commandline tool needs to acquire super user rights to
|
The tomb commandline tool needs to acquire super user rights to
|
||||||
execute most of its operations: to do so it uses sudo(8), while
|
execute most of its operations: so it uses sudo(8) or other configured
|
||||||
pinentry(1) is adopted to collect passwords from the user. Tomb
|
tools, while pinentry(1) is adopted to collect passwords from the
|
||||||
executes as super user only when required.
|
user. Tomb executes as super user only when required.
|
||||||
|
|
||||||
To be made available on multi user systems, the superuser execution of
|
To be made available on multi user systems, the superuser execution of
|
||||||
the tomb script can be authorized for users without jeopardizing the
|
the tomb script can be authorized for users without jeopardizing the
|
||||||
@ -294,14 +402,23 @@ whole system's security: just add such a line to \fI/etc/sudoers\fR:
|
|||||||
username ALL=NOPASSWD: /usr/local/bin/tomb
|
username ALL=NOPASSWD: /usr/local/bin/tomb
|
||||||
.EE
|
.EE
|
||||||
|
|
||||||
|
To avoid that tomb execution is logged by \fIsyslog\fR also add:
|
||||||
|
|
||||||
|
.EX
|
||||||
|
Cmnd_Alias TOMB = /usr/local/bin/tomb
|
||||||
|
Defaults!TOMB !syslog
|
||||||
|
.EE
|
||||||
|
|
||||||
|
.SH PASSWORD INPUT
|
||||||
|
|
||||||
Password input is handled by the pinentry program: it can be text
|
Password input is handled by the pinentry program: it can be text
|
||||||
based or graphical and is usually configured with a symlink. When
|
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
|
using Tomb in a graphical environment (X11 or Wayland) it is better
|
||||||
pinentry-qt because it helps preventing keylogging by other X
|
to use either pinentry-gtk2 (deprecated), pinentry-gnome or
|
||||||
clients. When using it from a remote ssh connection it might be
|
pinentry-qt because it helps preventing keylogging by other clients.
|
||||||
necessary to force use of pinentry-curses for instance by unsetting
|
When using it from a remote ssh connection it might be necessary to
|
||||||
the DISPLAY environment var.
|
force use of pinentry-tty for instance by unsetting the DISPLAY (X11)
|
||||||
|
or WAYLAND_DISPLAY (Wayland) environment var.
|
||||||
|
|
||||||
.SH SWAP
|
.SH SWAP
|
||||||
|
|
||||||
@ -324,6 +441,38 @@ If you don't need swap, execute \fI swapoff -a\fR. If you really need
|
|||||||
it, you could make an encrypted swap partition. Tomb doesn't detect if
|
it, you could make an encrypted swap partition. Tomb doesn't detect if
|
||||||
your swap is encrypted, and will complain anyway.
|
your swap is encrypted, and will complain anyway.
|
||||||
|
|
||||||
|
.SH DENIABILITY
|
||||||
|
|
||||||
|
The possibility to have an encrypted volume which is invisible and
|
||||||
|
cannot be detected is called "deniability". The cryptographic layer of
|
||||||
|
the device mapper in Linux (dm-crypt) does not implement
|
||||||
|
deniability. Tomb is just a wrapper on top of that and it doesn't add
|
||||||
|
cryptographic deniability. However a certain way of using tomb can
|
||||||
|
facilitate a weak sort of deniability outside of the scenario of
|
||||||
|
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 invocations of tomb with a blank space, including two lines
|
||||||
|
in ".zshrc":
|
||||||
|
|
||||||
|
.EX
|
||||||
|
export HISTIGNORESPACE=1
|
||||||
|
alias tomb=' tomb'
|
||||||
|
.EE
|
||||||
|
|
||||||
|
.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
|
||||||
|
using the \fI-r\fR (or/and \fI-R\fR) option and if multiple each GPG
|
||||||
|
key ID must be separated by a comma (\fI,\fR). Sharing a tomb is a
|
||||||
|
very sensitive action and the user needs to trust that all the GPG
|
||||||
|
public keys used are kept safe. If one of them its stolen or lost, it
|
||||||
|
will be always possible to use it to access the tomb key unless all
|
||||||
|
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 EXAMPLES
|
.SH EXAMPLES
|
||||||
|
|
||||||
.IP \(bu
|
.IP \(bu
|
||||||
@ -373,13 +522,14 @@ keeping all its profile data inside it:
|
|||||||
|
|
||||||
.EX
|
.EX
|
||||||
tomb open FOX.tomb -k FOX.tomb.key
|
tomb open FOX.tomb -k FOX.tomb.key
|
||||||
cat <<EOF > /media/FOX.tomb/post-hooks
|
cat <<EOF > /media/FOX.tomb/exec-hooks
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
if [ "$1" = "open" ]; then
|
if [ "$1" = "open" ]; then
|
||||||
firefox -no-remote -profile "$2"/firefox-pro &
|
firefox -no-remote -profile "$2"/firefox-pro &
|
||||||
fi
|
fi
|
||||||
EOF
|
EOF
|
||||||
chmod +x /media/FOX.tomb/post-hooks
|
chmod +x /media/FOX.tomb/exec-hooks
|
||||||
|
mkdir /media/FOX.tomb/firefox-pro
|
||||||
.EE
|
.EE
|
||||||
|
|
||||||
.IP \(bu
|
.IP \(bu
|
||||||
@ -390,7 +540,7 @@ Script a tomb to archive Pictures using Shotwell, launching it on open:
|
|||||||
cat <<EOF > /media/Pictures.tomb/bind-hooks
|
cat <<EOF > /media/Pictures.tomb/bind-hooks
|
||||||
Pictures Pictures
|
Pictures Pictures
|
||||||
EOF
|
EOF
|
||||||
cat <<EOF > /media/Pictures.tomb/post-hooks
|
cat <<EOF > /media/Pictures.tomb/exec-hooks
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
if [ "$1" = "open" ]; then
|
if [ "$1" = "open" ]; then
|
||||||
which shotwell > /dev/null
|
which shotwell > /dev/null
|
||||||
@ -399,7 +549,7 @@ if [ "$1" = "open" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
EOF
|
EOF
|
||||||
chmod +x /media/Pictures.tomb/post-hooks
|
chmod +x /media/Pictures.tomb/exec-hooks
|
||||||
.EE
|
.EE
|
||||||
|
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
@ -407,30 +557,12 @@ Please report bugs on the Github issue tracker at
|
|||||||
.UR https://github.com/dyne/Tomb/issues
|
.UR https://github.com/dyne/Tomb/issues
|
||||||
.UE
|
.UE
|
||||||
|
|
||||||
One can also try to get in touch with developers via the #dyne chat channel on \fIhttps://irc.dyne.org\fR.
|
One can also try to get in touch with developers via the #dyne chat
|
||||||
|
channel on \fIhttps://irc.dyne.org\fR.
|
||||||
.SH AUTHORS
|
|
||||||
|
|
||||||
Tomb is designed, written and maintained by Denis Roio aka Jaromil.
|
|
||||||
|
|
||||||
Tomb includes code by Anathema, Boyska, Hellekin O. Wolf and GDrooid.
|
|
||||||
|
|
||||||
Tomb's artwork is contributed by Jordi aka Mon Mort and Logan VanCuren.
|
|
||||||
|
|
||||||
Gettext internationalization and Spanish translation is contributed by
|
|
||||||
GDrooid, French translation by Hellekin, Russian translation by fsLeg,
|
|
||||||
German translation by x3nu.
|
|
||||||
|
|
||||||
Testing, reviews and documentation are contributed by Dreamer, Shining
|
|
||||||
the Translucent, Mancausoft, Asbesto Molesto, Nignux, Vlax, The Grugq,
|
|
||||||
Reiven, GDrooid, Alphazo, Brian May, TheJH, fsLeg, JoelMon and the
|
|
||||||
Linux Action Show!
|
|
||||||
|
|
||||||
Cryptsetup was developed by Christophe Saout and Clemens Fruhwirth.
|
|
||||||
|
|
||||||
.SH COPYING
|
.SH COPYING
|
||||||
|
|
||||||
This manual is Copyright (c) 2011-2015 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.
|
This manual includes contributions by Boyska and Hellekin O. Wolf.
|
||||||
|
|
||||||
@ -451,15 +583,13 @@ documentation is available for download from its website on
|
|||||||
|
|
||||||
.B
|
.B
|
||||||
.IP cryptsetup(8)
|
.IP cryptsetup(8)
|
||||||
|
.B
|
||||||
|
.IP pinentry(1)
|
||||||
|
.B
|
||||||
|
.IP gpg-agent(1)
|
||||||
|
|
||||||
GnuPG website:
|
GnuPG website: https://www.gnupg.org
|
||||||
.br
|
|
||||||
https://www.gnupg.org
|
|
||||||
|
|
||||||
DM-Crypt website:
|
DM-Crypt website: https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt
|
||||||
.br
|
|
||||||
https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt
|
|
||||||
|
|
||||||
LUKS website:
|
LUKS website: https://gitlab.com/cryptsetup/cryptsetup/wikis/home
|
||||||
.br
|
|
||||||
https://gitlab.com/cryptsetup/cryptsetup/wikis/home
|
|
||||||
|
Binary file not shown.
18
extras/android/README.txt
Normal file
18
extras/android/README.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
This is an experimental port of Tomb to Android platform
|
||||||
|
|
||||||
|
REQUIRES ROOT - see on-line docs on how to root Android.
|
||||||
|
|
||||||
|
This includes a static binary of cryptsetup to interact with the
|
||||||
|
dm-crypt Linux API for filesystem cryptography (ELF for ARMv6)
|
||||||
|
|
||||||
|
Tombs can be created and opened correctly
|
||||||
|
|
||||||
|
Only aes-cbc-essiv:sha254 crypto algo is supported.
|
||||||
|
|
||||||
|
At the moment tombs cannot be closed.
|
||||||
|
One has to reboot the device for that.
|
||||||
|
|
||||||
|
Other functions have not been tested.
|
||||||
|
|
||||||
|
More than ever, this is provided WITHOUT ANY WARRANTY
|
||||||
|
|
2760
extras/android/tomb
Executable file
2760
extras/android/tomb
Executable file
File diff suppressed because it is too large
Load Diff
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
|
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.
|
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
|
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`:
|
reported by `tomb list`. For instance if your tomb is `secrets.tomb`:
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
snprintf(filename,255, "%s", argv[1]);
|
snprintf(filename,255, "%s", argv[1]);
|
||||||
snprintf(mountpoint,255, "/media/%s.tomb", argv[1]);
|
snprintf(mountpoint,255, "/media/%s", argv[1]);
|
||||||
|
|
||||||
// libnotify
|
// libnotify
|
||||||
notify_init("Tomb");
|
notify_init("Tomb");
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
gtomb - A GUI wrapper for Tomb, the crypto undertaker
|
gtomb - A GUI wrapper for Tomb, the crypto undertaker
|
||||||
Copyright (C) 2015 Parazyd <parazyd AT dyne DOT org>
|
Copyright (C) 2015-2016 Parazyd <parazyd@dyne.org>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
@ -11,7 +11,7 @@ list and the script will run it for you. Easy-peasy.
|
|||||||
|
|
||||||
### Random notes
|
### Random notes
|
||||||
* If you type in your sudo password once correctly, in the next 5 (or whatever your sudoers timeout is) minutes, you can type in the wrong password as well.
|
* If you type in your sudo password once correctly, in the next 5 (or whatever your sudoers timeout is) minutes, you can type in the wrong password as well.
|
||||||
* The function for catching cancellation sometimes fails because of bad ps syntax. No idea why yet.
|
* The function for catching cancellation sometimes fails because of bad ps syntax. (Possibly fixed, needs more testing)
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
* [tomb](https://github.com/dyne/Tomb) (also get tomb's dependencies)
|
* [tomb](https://github.com/dyne/Tomb) (also get tomb's dependencies)
|
||||||
@ -19,8 +19,8 @@ list and the script will run it for you. Easy-peasy.
|
|||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
* Complete error checking
|
* Complete error checking
|
||||||
* Figure out why ps fails sometimes
|
|
||||||
* and more stuff
|
* and more stuff
|
||||||
|
|
||||||
## What you need to do
|
## What you need to do
|
||||||
* Be patient or help with coding :)
|
* Be patient or help with coding :)
|
||||||
|
* Request features
|
||||||
|
File diff suppressed because it is too large
Load Diff
11
extras/install_cloakify.sh
Executable file
11
extras/install_cloakify.sh
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -ex
|
||||||
|
wget https://github.com/TryCatchHCF/Cloakify/archive/v1.0.3.tar.gz -O /tmp/cloakify.tar.gz
|
||||||
|
mkdir -p extras/cloakify
|
||||||
|
tar -xvf /tmp/cloakify.tar.gz --strip-components=1 -C $PWD/extras/cloakify
|
||||||
|
echo "#!/bin/sh
|
||||||
|
python2 $PWD/extras/cloakify/cloakify.py $@" > /usr/bin/cloakify
|
||||||
|
echo "#!/bin/sh
|
||||||
|
python2 $PWD/extras/cloakify/decloakify.py $@" > /usr/bin/decloakify
|
||||||
|
chmod +x /usr/bin/cloakify
|
||||||
|
chmod +x /usr/bin/decloakify
|
@ -2,10 +2,14 @@
|
|||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(CC) -O2 -o tomb-kdb-pbkdf2 pbkdf2.c -lgcrypt
|
$(CC) -O2 $(CFLAGS) -o tomb-kdb-pbkdf2 pbkdf2.c -lgcrypt
|
||||||
$(CC) -O2 -o tomb-kdb-pbkdf2-getiter benchmark.c -lgcrypt
|
$(CC) -O2 $(CFLAGS) -o tomb-kdb-pbkdf2-getiter benchmark.c -lgcrypt
|
||||||
$(CC) -O2 -o tomb-kdb-pbkdf2-gensalt gen_salt.c -lgcrypt
|
$(CC) -O2 $(CFLAGS) -o tomb-kdb-pbkdf2-gensalt gen_salt.c -lgcrypt
|
||||||
$(CC) -O2 -o tomb-kdb-hexencode hexencode.c
|
$(CC) -O2 $(CFLAGS) -o tomb-kdb-hexencode hexencode.c
|
||||||
|
|
||||||
|
test:
|
||||||
|
@echo "Running Tomb-kdb tests"
|
||||||
|
./test.sh
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f tomb-kdb-pbkdf2 tomb-kdb-pbkdf2-getiter tomb-kdb-pbkdf2-gensalt tomb-kdb-hexencode
|
rm -f tomb-kdb-pbkdf2 tomb-kdb-pbkdf2-getiter tomb-kdb-pbkdf2-gensalt tomb-kdb-hexencode
|
||||||
|
@ -41,7 +41,7 @@ int main(int argc, char *argv[]) {
|
|||||||
} else {
|
} else {
|
||||||
while( (read_bytes=fread(buf, sizeof(char), 2, stdin)) != 0) {
|
while( (read_bytes=fread(buf, sizeof(char), 2, stdin)) != 0) {
|
||||||
if(read_bytes == 1) buf[1]='\0';
|
if(read_bytes == 1) buf[1]='\0';
|
||||||
sscanf(buf, "%x", &c);
|
sscanf(buf, "%s", &c);
|
||||||
printf("%c", c);
|
printf("%c", c);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
*************
|
*************
|
||||||
**
|
**
|
||||||
** Anthony Thyssen 4 November 2009 A.Thyssen@griffith.edu.au
|
** Anthony Thyssen 4 November 2009 A.Thyssen@griffith.edu.au
|
||||||
|
** AitorATuin 3 February 2018 (whitespace password fix in Tomb)
|
||||||
**
|
**
|
||||||
** Based on a test program "pkcs5.c" found on
|
** Based on a test program "pkcs5.c" found on
|
||||||
** http://www.mail-archive.com/openssl-users@openssl.org
|
** http://www.mail-archive.com/openssl-users@openssl.org
|
||||||
@ -43,6 +44,9 @@
|
|||||||
|
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
|
|
||||||
|
/* block size for password buffer */
|
||||||
|
#define BLOCK_SIZE 40
|
||||||
|
|
||||||
/* TODO: move print_hex and hex_to_binary to utils.h, with separate compiling */
|
/* TODO: move print_hex and hex_to_binary to utils.h, with separate compiling */
|
||||||
void print_hex(unsigned char *buf, int len)
|
void print_hex(unsigned char *buf, int len)
|
||||||
{
|
{
|
||||||
@ -73,15 +77,37 @@ int hex_to_binary(unsigned char *buf, char *hex)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cleanup(char *result, int result_len, char *pass, char *salt, int salt_len) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
//clear and free everything
|
||||||
|
if (result) {
|
||||||
|
for(i=0; i<result_len;i++)
|
||||||
|
result[i]=0;
|
||||||
|
free(result);
|
||||||
|
}
|
||||||
|
if (pass) {
|
||||||
|
for(i=0; i<strlen(pass); i++) //blank
|
||||||
|
pass[i]=0;
|
||||||
|
free(pass);
|
||||||
|
}
|
||||||
|
if (salt) {
|
||||||
|
for(i=0; i<salt_len; i++) //blank
|
||||||
|
salt[i]=0;
|
||||||
|
free(salt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char *pass = NULL;
|
char *pass = NULL;
|
||||||
unsigned char *salt;
|
unsigned char *salt = NULL;
|
||||||
int salt_len; // salt length in bytes
|
int salt_len; // salt length in bytes
|
||||||
int ic=0; // iterative count
|
int ic=0; // iterative count
|
||||||
int result_len;
|
int result_len;
|
||||||
unsigned char *result; // result (binary - 32+16 chars)
|
unsigned char *result = NULL; // result (binary - 32+16 chars)
|
||||||
int i;
|
int i, pw_len = 0;
|
||||||
|
int buff_len = BLOCK_SIZE;
|
||||||
|
|
||||||
if ( argc != 4 ) {
|
if ( argc != 4 ) {
|
||||||
fprintf(stderr, "usage: %s salt count len <passwd >binary_key_iv\n", argv[0]);
|
fprintf(stderr, "usage: %s salt count len <passwd >binary_key_iv\n", argv[0]);
|
||||||
@ -89,7 +115,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: move to base64decode
|
//TODO: move to base64decode
|
||||||
salt=calloc(strlen(argv[1])/2+3, sizeof(char));
|
salt_len = strlen(argv[1])/2+3;
|
||||||
|
salt = calloc(salt_len, sizeof(char));
|
||||||
salt_len=hex_to_binary(salt, argv[1]);
|
salt_len=hex_to_binary(salt, argv[1]);
|
||||||
if( salt_len <= 0 ) {
|
if( salt_len <= 0 ) {
|
||||||
fprintf(stderr, "Error: %s is not a valid salt (it must be a hexadecimal string)\n", argv[1]);
|
fprintf(stderr, "Error: %s is not a valid salt (it must be a hexadecimal string)\n", argv[1]);
|
||||||
@ -105,14 +132,41 @@ int main(int argc, char *argv[])
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fscanf(stdin, "%ms", &pass);
|
/* Read password char by char.
|
||||||
if ( pass[strlen(pass)-1] == '\n' )
|
*
|
||||||
pass[strlen(pass)-1] = '\0';
|
* Doing in this way we make sure that blanks (even null bytes) end up
|
||||||
|
* in the password.
|
||||||
|
*
|
||||||
|
* passwords containing just a bunch of spaces are valid
|
||||||
|
*/
|
||||||
|
pass = calloc(buff_len, sizeof(char));
|
||||||
|
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\n");
|
||||||
|
cleanup(result, result_len, pass, salt, salt_len);
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pass[pw_len] = (char)c;
|
||||||
|
pw_len++;
|
||||||
|
c = getchar();
|
||||||
|
}
|
||||||
|
if (pw_len <= 1) {
|
||||||
|
fprintf(stderr, "Error: password is empty\n");
|
||||||
|
cleanup(result, result_len, pass, salt, salt_len);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
pass[pw_len-1] = '\0';
|
||||||
|
|
||||||
// PBKDF 2
|
// PBKDF 2
|
||||||
result = calloc(result_len, sizeof(unsigned char*));
|
result = calloc(result_len, sizeof(unsigned char*));
|
||||||
if (!gcry_check_version ("1.5.0")) {
|
if (!gcry_check_version ("1.5.0")) {
|
||||||
fputs ("libgcrypt version mismatch\n", stderr);
|
fputs ("libgcrypt version mismatch\n", stderr);
|
||||||
|
cleanup(result, result_len, pass, salt, salt_len);
|
||||||
exit (2);
|
exit (2);
|
||||||
}
|
}
|
||||||
/* Allocate a pool of 16k secure memory. This make the secure memory
|
/* Allocate a pool of 16k secure memory. This make the secure memory
|
||||||
@ -124,19 +178,10 @@ int main(int argc, char *argv[])
|
|||||||
/* Tell Libgcrypt that initialization has completed. */
|
/* Tell Libgcrypt that initialization has completed. */
|
||||||
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
|
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||||
|
|
||||||
gcry_kdf_derive( pass, strlen(pass), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, salt, salt_len, ic, result_len, result);
|
gcry_kdf_derive(pass, pw_len-1, GCRY_KDF_PBKDF2, GCRY_MD_SHA1, salt, salt_len, ic, result_len, result);
|
||||||
print_hex(result, result_len); // Key + IV (as hex string)
|
print_hex(result, result_len); // Key + IV (as hex string)
|
||||||
|
|
||||||
//clear and free everything
|
cleanup(result, result_len, pass, salt, salt_len);
|
||||||
for(i=0; i<result_len;i++)
|
|
||||||
result[i]=0;
|
|
||||||
free(result);
|
|
||||||
for(i=0; i<strlen(pass); i++) //blank
|
|
||||||
pass[i]=0;
|
|
||||||
free(pass);
|
|
||||||
for(i=0; i<strlen(argv[1])/2+3; i++) //blank
|
|
||||||
salt[i]=0;
|
|
||||||
free(salt);
|
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
48
extras/kdf-keys/test.sh
Normal file → Executable file
48
extras/kdf-keys/test.sh
Normal file → Executable file
@ -1,6 +1,8 @@
|
|||||||
#!/usr/bin/env zsh
|
#!/usr/bin/env zsh
|
||||||
|
|
||||||
error=0
|
error=0
|
||||||
|
|
||||||
|
check_kdf() {
|
||||||
while read line; do
|
while read line; do
|
||||||
pass=`cut -f1 <<<$line`
|
pass=`cut -f1 <<<$line`
|
||||||
salt=`cut -f2 <<<$line`
|
salt=`cut -f2 <<<$line`
|
||||||
@ -9,13 +11,55 @@ while read line; do
|
|||||||
expected=`cut -f5 <<<$line`
|
expected=`cut -f5 <<<$line`
|
||||||
hexsalt=`cut -f6 <<<$line`
|
hexsalt=`cut -f6 <<<$line`
|
||||||
#TODO: check!
|
#TODO: check!
|
||||||
derived=`./pbkdf2 $hexsalt $iter $keylen <<<$pass`
|
derived=`./tomb-kdb-pbkdf2 $hexsalt $iter $keylen <<<$pass`
|
||||||
if [[ $derived != $expected ]]; then
|
if [[ $derived != $expected ]]; then
|
||||||
echo ./pbkdf2 $hexsalt $iter $keylen "<<<$pass"
|
|
||||||
echo "Expected $expected, got $derived" >&2
|
echo "Expected $expected, got $derived" >&2
|
||||||
error=$((error + 1))
|
error=$((error + 1))
|
||||||
fi
|
fi
|
||||||
done < test.txt
|
done < test.txt
|
||||||
|
}
|
||||||
|
|
||||||
|
check_white_spaces() {
|
||||||
|
hexsalt="73616c74"
|
||||||
|
iter=4096
|
||||||
|
keylen=20
|
||||||
|
typeset -a results
|
||||||
|
passwords=('one two three' 'one two' 'one')
|
||||||
|
for pwd in $passwords; do
|
||||||
|
results+=`./tomb-kdb-pbkdf2 $hexsalt $iter $keylen <<<$pwd`
|
||||||
|
done
|
||||||
|
for ((i=1;i<=3;i++)); do
|
||||||
|
d1=$results[$i]
|
||||||
|
i1=$passwords[$i]
|
||||||
|
for ((j=(($i+1));j<=3;j++)); do
|
||||||
|
d2=$results[$j]
|
||||||
|
i2=$passwords[$j]
|
||||||
|
if [[ $d1 == $d2 ]]; then
|
||||||
|
echo "Inputs \"$i1\" and \"$i2\" produce the same output $d1" >&2
|
||||||
|
error=$((error + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
check_password_len() {
|
||||||
|
hexsalt="73616c74"
|
||||||
|
iter=4096
|
||||||
|
keylen=20
|
||||||
|
./tomb-kdb-pbkdf2 $hexsalt $iter $keylen 2>/dev/null <<<"" && {
|
||||||
|
echo "Empty passwords are accepted"
|
||||||
|
error=$((error + 1))
|
||||||
|
}
|
||||||
|
bigpassword=`perl -e 'print "a"x3000'`
|
||||||
|
./tomb-kdb-pbkdf2 $hexsalt $iter $keylen &>/dev/null <<<"$bigpassword" || {
|
||||||
|
echo "Error when using long password"
|
||||||
|
error=$((error + 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check_kdf
|
||||||
|
check_white_spaces
|
||||||
|
check_password_len
|
||||||
|
|
||||||
if [[ $error == 1 ]]; then
|
if [[ $error == 1 ]]; then
|
||||||
exit $error
|
exit $error
|
||||||
|
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"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user