cronos-extract 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cronos_extract-1.0.0/LICENSE +22 -0
- cronos_extract-1.0.0/PKG-INFO +394 -0
- cronos_extract-1.0.0/README.md +367 -0
- cronos_extract-1.0.0/pyproject.toml +96 -0
- cronos_extract-1.0.0/pyproject.toml.orig +70 -0
- cronos_extract-1.0.0/src/cronos_extract/Database.py +374 -0
- cronos_extract-1.0.0/src/cronos_extract/Datafile.py +263 -0
- cronos_extract-1.0.0/src/cronos_extract/Datamodel.py +301 -0
- cronos_extract-1.0.0/src/cronos_extract/__init__.py +65 -0
- cronos_extract-1.0.0/src/cronos_extract/_api/__init__.py +2 -0
- cronos_extract-1.0.0/src/cronos_extract/_api/bank.py +439 -0
- cronos_extract-1.0.0/src/cronos_extract/_api/crack.py +151 -0
- cronos_extract-1.0.0/src/cronos_extract/_api/datafiles.py +120 -0
- cronos_extract-1.0.0/src/cronos_extract/_api/diagnostics.py +115 -0
- cronos_extract-1.0.0/src/cronos_extract/_api/errors.py +22 -0
- cronos_extract-1.0.0/src/cronos_extract/_api/info.py +79 -0
- cronos_extract-1.0.0/src/cronos_extract/_api/kod.py +54 -0
- cronos_extract-1.0.0/src/cronos_extract/_api/values.py +209 -0
- cronos_extract-1.0.0/src/cronos_extract/_cli/__init__.py +2 -0
- cronos_extract-1.0.0/src/cronos_extract/_cli/crack.py +417 -0
- cronos_extract-1.0.0/src/cronos_extract/_cli/csv_out.py +141 -0
- cronos_extract-1.0.0/src/cronos_extract/_cli/export.py +287 -0
- cronos_extract-1.0.0/src/cronos_extract/_cli/inspect.py +250 -0
- cronos_extract-1.0.0/src/cronos_extract/_cli/jsonl_out.py +83 -0
- cronos_extract-1.0.0/src/cronos_extract/_cli/names.py +58 -0
- cronos_extract-1.0.0/src/cronos_extract/_cli/options.py +73 -0
- cronos_extract-1.0.0/src/cronos_extract/_cli/report.py +201 -0
- cronos_extract-1.0.0/src/cronos_extract/_cli/sql_out.py +128 -0
- cronos_extract-1.0.0/src/cronos_extract/_diagnostic.py +59 -0
- cronos_extract-1.0.0/src/cronos_extract/_format/__init__.py +2 -0
- cronos_extract-1.0.0/src/cronos_extract/_format/files.py +35 -0
- cronos_extract-1.0.0/src/cronos_extract/_format/header.py +92 -0
- cronos_extract-1.0.0/src/cronos_extract/_format/record.py +192 -0
- cronos_extract-1.0.0/src/cronos_extract/_format/tad.py +103 -0
- cronos_extract-1.0.0/src/cronos_extract/cli.py +144 -0
- cronos_extract-1.0.0/src/cronos_extract/hexdump.py +122 -0
- cronos_extract-1.0.0/src/cronos_extract/koddecoder.py +456 -0
- cronos_extract-1.0.0/src/cronos_extract/kodump.py +87 -0
- cronos_extract-1.0.0/src/cronos_extract/py.typed +0 -0
- cronos_extract-1.0.0/src/cronos_extract/readers.py +111 -0
- cronos_extract-1.0.0/src/cronos_extract/survey.py +144 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Organized Crime and Corruption Reporting Project
|
|
4
|
+
Copyright (c) 2026 Ben Hammersley
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cronos-extract
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Extract data from CronosPro databases, including password-protected ones.
|
|
5
|
+
Keywords: cronos,cronospro,database,export,forensics
|
|
6
|
+
Author: Willem Hengeveld, Dirk Engling, Ben Hammersley
|
|
7
|
+
Author-email: Willem Hengeveld <itsme@xs4all.nl>, Dirk Engling <erdgeist@erdgeist.org>, Ben Hammersley <ben@hammersleyfutures.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Database
|
|
20
|
+
Classifier: Topic :: Utilities
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Project-URL: Homepage, https://github.com/hammersleyfutures/cronos-extract
|
|
23
|
+
Project-URL: Documentation, https://github.com/hammersleyfutures/cronos-extract/blob/main/docs/api.md
|
|
24
|
+
Project-URL: Changelog, https://github.com/hammersleyfutures/cronos-extract/blob/main/CHANGELOG.md
|
|
25
|
+
Project-URL: Issues, https://github.com/hammersleyfutures/cronos-extract/issues
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# cronos-extract
|
|
29
|
+
|
|
30
|
+
cronos-extract reads most databases of the [CronosPro](https://www.cronos.ru/) database software. It exports their
|
|
31
|
+
tables to CSV, PostgreSQL or JSON Lines. It also shows their internal structures, and it recovers the KOD of an
|
|
32
|
+
encrypted database.
|
|
33
|
+
|
|
34
|
+
CronosPro is popular among Russian public offices, companies and police agencies.
|
|
35
|
+
|
|
36
|
+
cronos-extract continues [cronodump](https://github.com/alephdata/cronodump) by Willem Hengeveld and Dirk Engling.
|
|
37
|
+
The Organized Crime and Corruption Reporting Project (OCCRP) published cronodump. cronos-extract starts from the
|
|
38
|
+
`master` branch of cronodump, together with the assisted KOD recovery of
|
|
39
|
+
[alephdata/cronodump#13](https://github.com/alephdata/cronodump/pull/13). This repository keeps the full history of
|
|
40
|
+
cronodump. The [changelog](https://github.com/hammersleyfutures/cronos-extract/blob/main/CHANGELOG.md) tells what is
|
|
41
|
+
different in cronos-extract.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
cronos-extract needs Python 3.12 or later. It has no other dependencies. The package on PyPI is `cronos-extract`.
|
|
47
|
+
|
|
48
|
+
To install the `cronos-extract` command, use one of these commands:
|
|
49
|
+
|
|
50
|
+
- With uv: `uv tool install cronos-extract`
|
|
51
|
+
- With pipx: `pipx install cronos-extract`
|
|
52
|
+
- With pip, in a virtual environment: `pip install cronos-extract`
|
|
53
|
+
|
|
54
|
+
To make sure that the command is installed, show its version:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
cronos-extract --version
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The command prints its name and version, for example `cronos-extract 1.0.0`.
|
|
61
|
+
|
|
62
|
+
In a clone of this repository, you can use `uv run cronos-extract` in place of `cronos-extract`. The examples that
|
|
63
|
+
name `test_data` use the test database of the repository. They work only in a clone.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
To export each table of the test database to a CSV file, use this command:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
cronos-extract export --csv test_data/all_field_types
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The command creates the directory `cronos-extract-YYYY-mm-dd-HH-MM-SS-ffffff/` in the current directory. This
|
|
75
|
+
directory holds:
|
|
76
|
+
|
|
77
|
+
- A CSV file for each table.
|
|
78
|
+
- `Files-<abbreviation>/` (the Files table's abbreviation, `Files-FL/` for the test database), with each file that
|
|
79
|
+
the database stores. This includes the files that no record refers to.
|
|
80
|
+
- `Files-Referenced/`, with the files that the records refer to, under their own names.
|
|
81
|
+
|
|
82
|
+
`Files-Referenced/` appears at the first record of a table with a file field. It also appears for a record whose
|
|
83
|
+
file field is empty.
|
|
84
|
+
|
|
85
|
+
To give the directory a different name, use `-o DIR`. The directory must not exist, because the export never
|
|
86
|
+
overwrites a file or a directory.
|
|
87
|
+
|
|
88
|
+
If the export stops with an error about the database definition or the KOD, the database is probably encrypted with
|
|
89
|
+
its own KOD. If the output is unreadable, the same is probably true. In both cases, refer to "Recover the KOD of an
|
|
90
|
+
encrypted database" below.
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
## Export
|
|
94
|
+
|
|
95
|
+
`cronos-extract export` writes every table of a database in one of three formats: `--csv`, `--postgres` or
|
|
96
|
+
`--jsonl`.
|
|
97
|
+
|
|
98
|
+
### Diagnostics
|
|
99
|
+
|
|
100
|
+
The export continues after each problem that it survives, for example a corrupt record. For each such problem, it
|
|
101
|
+
writes one `warning:` line on stderr at the time that the problem occurs. This line is a diagnostic. The last line
|
|
102
|
+
of stderr gives the number of diagnostics of each kind:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
warning: corrupt_record: CroBank.dat record 88: CroBank record 88 is corrupt and is skipped: EOFError
|
|
106
|
+
|
|
107
|
+
1 diagnostic: 1 corrupt_record
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The export keeps a compressed record whose CRC-32 does not agree with its data. It reports this record as
|
|
111
|
+
`checksum_mismatch`. If a record decompresses to more than 256 MiB, the export skips it and reports it as
|
|
112
|
+
`corrupt_record`.
|
|
113
|
+
|
|
114
|
+
The `.tad` file of CroBank can list deleted records. The export does not write deleted records. It writes one
|
|
115
|
+
`note:` line with their number on stderr, before the first table:
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
note: CroBank.tad lists 85 deleted records, which are not exported; inspect crodump shows what remains of them
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This note is not a diagnostic, and it does not change the exit status.
|
|
122
|
+
|
|
123
|
+
### Exit status
|
|
124
|
+
|
|
125
|
+
The export exits with one of these statuses:
|
|
126
|
+
|
|
127
|
+
- 0: The export is complete, with or without diagnostics.
|
|
128
|
+
- 1: The export failed, for example because it cannot read the database. The last line on stderr is one `Error:`
|
|
129
|
+
line.
|
|
130
|
+
- 2: The options or arguments are not correct, or the output exists already.
|
|
131
|
+
- 130: The export stopped because you pressed Ctrl-C.
|
|
132
|
+
|
|
133
|
+
If the export stops after it created its output, the `Error:` line tells where the partial output is.
|
|
134
|
+
|
|
135
|
+
If the export gets `--strict` and reports a diagnostic, it exits with 1. It writes all of the output first. The test
|
|
136
|
+
database reports that its table definitions have an unexpected layout. Thus `--strict` exits with 1 for it:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
cronos-extract export --csv --strict -o strict test_data/all_field_types # exits 1, because of the diagnostics
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The header of a v4 Cro file shows when a KOD is not the KOD of the database. If the header rejects the KOD, the
|
|
143
|
+
export stops and exits with 1. Its `Error:` line names the `export --crack` method that can recover the correct KOD.
|
|
144
|
+
If the database definition cannot be decoded, the `Error:` line names `cronos-extract crack strucrack`.
|
|
145
|
+
|
|
146
|
+
### Terminal safety
|
|
147
|
+
|
|
148
|
+
The names and values of a database can hold characters that a terminal interprets. For this reason, do not write
|
|
149
|
+
the PostgreSQL or JSON Lines export to a terminal. Write it to a file with `-o FILE`. The file must not exist.
|
|
150
|
+
|
|
151
|
+
The command escapes all text that it writes on stderr. Thus stderr is safe for a terminal.
|
|
152
|
+
|
|
153
|
+
### CSV
|
|
154
|
+
|
|
155
|
+
`--csv` creates a directory with one `<table name>.csv` file for each table. The files are UTF-8 without a byte order
|
|
156
|
+
mark. The first row holds the field names. The first field is the system number.
|
|
157
|
+
|
|
158
|
+
`--delimiter ';'` sets a different delimiter. The default delimiter is a comma. `--no-files` does not write the two
|
|
159
|
+
file directories.
|
|
160
|
+
|
|
161
|
+
In a file name, the export replaces path separators with underscores. It also replaces the characters that no file
|
|
162
|
+
system accepts. Each file name is unique in the directory and at most 255 bytes long.
|
|
163
|
+
|
|
164
|
+
The cells hold exactly what the database holds. This includes text that a spreadsheet reads as a formula.
|
|
165
|
+
|
|
166
|
+
Open a CSV file with the CSV import of the spreadsheet, as UTF-8. Do not open it with a double-click.
|
|
167
|
+
|
|
168
|
+
### PostgreSQL
|
|
169
|
+
|
|
170
|
+
`--postgres` writes a `CREATE TABLE` statement for each table and an `INSERT` statement for each record. Each column
|
|
171
|
+
has the type `TEXT`, the system number included. Thus every record loads, also a record with a value that does not
|
|
172
|
+
agree with its field type.
|
|
173
|
+
|
|
174
|
+
The export writes each value as it decodes it: dates as `YYYY-MM-DD`, times as `HH:MM`, and empty values as `NULL`.
|
|
175
|
+
If you need types, cast the columns in SQL, for example `"Entry #4"::date`.
|
|
176
|
+
|
|
177
|
+
The output starts with `SET standard_conforming_strings = on;`. Thus its string literals load correctly with each
|
|
178
|
+
setting of the server. PostgreSQL text cannot hold a NUL character. The export writes a NUL in a value as U+FFFD and
|
|
179
|
+
reports it as `replaced_nul`.
|
|
180
|
+
|
|
181
|
+
The PostgreSQL export does not include the stored files. Use `--csv` for them.
|
|
182
|
+
|
|
183
|
+
### JSON Lines
|
|
184
|
+
|
|
185
|
+
`--jsonl` writes one JSON object on each line:
|
|
186
|
+
|
|
187
|
+
- A `table` line before the records of each table.
|
|
188
|
+
- A `record` line for each record.
|
|
189
|
+
- A `diagnostic` line for each diagnostic, at the position where it occurred.
|
|
190
|
+
- A `deleted_records` line before the first table, with the number of deleted records that CroBank lists.
|
|
191
|
+
|
|
192
|
+
If CroBank lists no deleted records, the `deleted_records` line is not there.
|
|
193
|
+
|
|
194
|
+
Thus a script can find the records with diagnostics. It does not have to read stderr.
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{"type": "table", "table": "Люди", "table_id": 1, "abbreviation": "ЛЮ", "fields": [{"name": "Системный номер", "type": 0}, {"name": "ФИО", "type": 2}]}
|
|
198
|
+
{"type": "record", "table": "Люди", "table_id": 1, "record": 12, "fields": [{"name": "Системный номер", "value": "3"}, {"name": "ФИО", "value": "Иванов"}]}
|
|
199
|
+
{"type": "diagnostic", "kind": "invalid_value", "message": "the value is not a date; it is kept as text", "file": "CroBank.dat", "table": "Люди", "record": 13, "field": "Дата"}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Each record line names its table and its fields, in the order that the table defines them. Thus you can read each
|
|
203
|
+
line alone. The `value` of a field is one of these:
|
|
204
|
+
|
|
205
|
+
- `null` for an empty field.
|
|
206
|
+
- A date as `"1985-04-02"`. A date with only its year is `"1985-00-00"`.
|
|
207
|
+
- A time as `"14:30"`.
|
|
208
|
+
- `{"name": …, "extension": …, "record": …}` for a stored file.
|
|
209
|
+
- The text of the field for all other fields.
|
|
210
|
+
|
|
211
|
+
The JSON Lines export does not include the stored files. Use `--csv` for them.
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
cronos-extract export --jsonl -o people.jsonl test_data/all_field_types
|
|
215
|
+
jq -r 'select(.type == "record") | .fields[] | select(.name == "Entry #1") | .value' people.jsonl
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Large databases
|
|
219
|
+
|
|
220
|
+
The `.tad` files of a very large database can use gigabytes of memory. `--compact` reads the `.tad` files of CroStru
|
|
221
|
+
and CroBank from the disk, in place of memory. With `--compact`, the export is approximately 15% slower. Use
|
|
222
|
+
`--compact` for a very large database.
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
## Survey
|
|
226
|
+
|
|
227
|
+
`cronos-extract survey` tells which CronosPro version each database uses. It reads only the 19-byte header of each
|
|
228
|
+
`Cro*.dat` file. It does not read records or file contents. Thus you can survey databases before you export them.
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
cronos-extract survey /path/to/databases # a block of text for each database
|
|
232
|
+
cronos-extract survey --counts /path/to/databases # totals only, with no directory names
|
|
233
|
+
cronos-extract survey --jsonl /path/to/databases # one JSON object for each database, for scripts
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
`--counts` gives the number of files of each version and generation. If the survey cannot read a header, `--counts`
|
|
237
|
+
also gives an `unreadable files: N` line at the end.
|
|
238
|
+
|
|
239
|
+
To survey databases in different directories as one group, do these steps:
|
|
240
|
+
|
|
241
|
+
1. Write the paths of the directories in a text file, one path on each line.
|
|
242
|
+
2. Give this file to `survey` with `--list`.
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
cronos-extract survey --list /path/to/list.txt --counts
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The survey ignores blank lines and lines that start with `#`. A relative path starts from the current directory. If
|
|
249
|
+
a path is not a directory, the survey reports it on stderr and skips it. It does the same for a directory that it
|
|
250
|
+
cannot list. The survey reports a database under two of the paths only one time.
|
|
251
|
+
|
|
252
|
+
Versions `01.02` to `01.05` are v3. Versions `01.11`, `01.13` and `01.14` are v4. Version `01.19` is v7. The survey
|
|
253
|
+
reports each version that it finds, also v7 and the versions that it does not know. The `export` and `inspect`
|
|
254
|
+
commands read v3 and v4, but not v7.
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
## Inspect
|
|
258
|
+
|
|
259
|
+
`cronos-extract inspect` shows what the export does not show, for a study of the file format. Experience with binary
|
|
260
|
+
dumps is helpful, because some parts of the format are not known.
|
|
261
|
+
|
|
262
|
+
The `inspect` subcommands write the names and bytes of the database to stdout without escapes. If the database is
|
|
263
|
+
untrusted, write their output to a file or to a pager. Do not write it to a terminal.
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
cronos-extract inspect strudump -v -a test_data/all_field_types # the database and table definitions, as text
|
|
267
|
+
cronos-extract inspect crodump -v test_data/all_field_types # each Cro file, one byte range after the other
|
|
268
|
+
cronos-extract inspect recdump test_data/all_field_types # a hexdump of each CroBank record
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
`recdump --stru`, `--index` or `--sys` dumps the records of that file in place of CroBank. `destruct` decodes a
|
|
272
|
+
definition that it gets as hex on stdin. `kodump` KOD-decodes a byte range of a file. Each subcommand shows its
|
|
273
|
+
options with `--help`.
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
## Recover the KOD of an encrypted database
|
|
277
|
+
|
|
278
|
+
CronosPro can protect a database with a password. The database is then encrypted with its own KOD, in place of the
|
|
279
|
+
default KOD. `cronos-extract crack` recovers this KOD from the encrypted records, without the password. Its two
|
|
280
|
+
methods are statistical. They do not always find every entry of the KOD.
|
|
281
|
+
|
|
282
|
+
### dbcrack
|
|
283
|
+
|
|
284
|
+
`crack dbcrack` reads the fourth byte of the CroBank and CroIndex records. This byte decodes to zero in a compressed
|
|
285
|
+
record. With `--silent`, dbcrack prints only the KOD. If dbcrack cannot find every entry, it exits with 1.
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
KOD=$(cronos-extract crack dbcrack --silent /path/to/database)
|
|
289
|
+
cronos-extract export --csv --kod "$KOD" /path/to/database
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### strucrack
|
|
293
|
+
|
|
294
|
+
`crack strucrack` reads CroStru, because most bytes of CroStru are zero. If strucrack cannot find every entry, it
|
|
295
|
+
shows the records as far as it can decode them. It suggests `-f` switches where it recognizes known text. Then it
|
|
296
|
+
writes the missing entries and its estimate of the KOD on stderr.
|
|
297
|
+
|
|
298
|
+
To find the missing entries, do these steps:
|
|
299
|
+
|
|
300
|
+
1. Add the suggested `-f` switches to the command.
|
|
301
|
+
2. If you can read text in a record, add `--text record:line:offset:plaintext` for this text.
|
|
302
|
+
3. Run strucrack again.
|
|
303
|
+
4. If strucrack does not print the KOD, do steps 1 to 3 again.
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
cronos-extract crack strucrack /path/to/database
|
|
307
|
+
cronos-extract crack strucrack -f f103=B -f f10342 /path/to/database
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
If strucrack gets `--noninteractive` and cannot find every entry, it exits with 1. Without `--noninteractive`, it
|
|
311
|
+
exits with 0 in this case.
|
|
312
|
+
|
|
313
|
+
### The KOD options
|
|
314
|
+
|
|
315
|
+
`--kod HEX` gives the KOD as 512 hex digits. cronos-extract uses this KOD only for a file that is encrypted with its
|
|
316
|
+
own KOD. These files are versions `01.04`, `01.05` and all v4 versions. `--nokod` reads the records without KOD
|
|
317
|
+
decoding.
|
|
318
|
+
|
|
319
|
+
`export --crack dbcrack` or `export --crack strucrack` recovers the KOD and exports with it in one step. If the method
|
|
320
|
+
cannot recover the KOD, the export exits with 1. The `strudump`, `recdump` and `crodump` subcommands of `inspect` also
|
|
321
|
+
take `--crack`.
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
## Python library
|
|
325
|
+
|
|
326
|
+
cronos-extract is also a Python library. The `export` command uses this library.
|
|
327
|
+
|
|
328
|
+
```python
|
|
329
|
+
import cronos_extract
|
|
330
|
+
|
|
331
|
+
with cronos_extract.open("path/to/database") as bank:
|
|
332
|
+
for table in bank.tables:
|
|
333
|
+
for record in table.records():
|
|
334
|
+
print(record["Entry #4"].value)
|
|
335
|
+
print(bank.diagnostic_counts)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
`open()` takes `kod=` (a `cronos_extract.Kod`, or `None` for no KOD decoding), `compact=True` for very large
|
|
339
|
+
databases, and `on_diagnostic=`. `on_diagnostic` is a function that receives each diagnostic. The library never
|
|
340
|
+
prints. It skips each record that it cannot read, and it reports the record as a diagnostic.
|
|
341
|
+
|
|
342
|
+
For a database that it cannot read, `open()` raises a `cronos_extract.CronosError` or an `OSError`.
|
|
343
|
+
`cronos_extract.crack_kod(path, "strucrack")` or `"dbcrack"` recovers the KOD of a database that is encrypted with its
|
|
344
|
+
own KOD.
|
|
345
|
+
|
|
346
|
+
The [API reference](https://github.com/hammersleyfutures/cronos-extract/blob/main/docs/api.md) documents each public
|
|
347
|
+
name, each diagnostic kind and the promises of the API.
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
## Terminology
|
|
351
|
+
|
|
352
|
+
cronos-extract uses the usual words for databases, tables, records and fields. CronosPro uses different words:
|
|
353
|
+
|
|
354
|
+
| cronos-extract | CronosPro in English | CronosPro in Russian |
|
|
355
|
+
|:---------------|:---------------------|:---------------------|
|
|
356
|
+
| database | Bank | Банк |
|
|
357
|
+
| table | Base | Базы |
|
|
358
|
+
| record | Record | Записи |
|
|
359
|
+
| field | Field | поля |
|
|
360
|
+
| system number | System Number | Системный номер |
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
## Development
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
uv sync # create the virtual environment with the development tools
|
|
367
|
+
uv run pre-commit install # lint, format, type-check and test before each commit
|
|
368
|
+
uv run pytest -q # run the tests
|
|
369
|
+
uv run ruff check && uv run ruff format --check && uv run ty check
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
The characterisation tests in `tests/test_cli_characterisation.py` compare the output of the commands with the files
|
|
373
|
+
in `tests/golden/`. After a deliberate change of the output, run `uv run pytest --update-golden`. Then examine the
|
|
374
|
+
changes to the golden files before you commit them.
|
|
375
|
+
|
|
376
|
+
`tests/test_readme.py` runs each `cronos-extract` command in the `bash` blocks of this README. If a link in this
|
|
377
|
+
README is not an absolute URL, the test fails. PyPI shows this README, and a relative link does not work there.
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
## License
|
|
381
|
+
|
|
382
|
+
The [MIT license](https://github.com/hammersleyfutures/cronos-extract/blob/main/LICENSE) applies to cronos-extract.
|
|
383
|
+
The license keeps the copyright notice of cronodump.
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
## References
|
|
387
|
+
|
|
388
|
+
cronodump used the [documentation of the file format in older versions of Cronos](http://sergsv.narod.ru/cronos.htm).
|
|
389
|
+
It also used the [parser for the old file format](https://github.com/occrp/cronosparser) that came after this
|
|
390
|
+
documentation. That parser guesses offsets and obfuscation parameters with heuristics. cronodump replaced these
|
|
391
|
+
guesses with a stricter parser.
|
|
392
|
+
|
|
393
|
+
The [research notes](https://github.com/hammersleyfutures/cronos-extract/blob/main/docs/cronos-research.md) of this
|
|
394
|
+
repository document the file format.
|