golemorph 1.1.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.
- golemorph-1.1.0/LICENSE +21 -0
- golemorph-1.1.0/PKG-INFO +197 -0
- golemorph-1.1.0/README.md +182 -0
- golemorph-1.1.0/golemorph/__init__.py +29 -0
- golemorph-1.1.0/golemorph/__main__.py +6 -0
- golemorph-1.1.0/golemorph/cli.py +272 -0
- golemorph-1.1.0/golemorph/data/ALG/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/ALG/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/ARG/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/ARG/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/AUT/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/AUT/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/BEL/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/BEL/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/BGR/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/BGR/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/BRA/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/BRA/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/CAN/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/CAN/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/CHN/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/CHN/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/COL/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/COL/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/CZE/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/CZE/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/DEU/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/DEU/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/DNK/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/DNK/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/EGY/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/EGY/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/ESP/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/ESP/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/FIN/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/FIN/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/FRA/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/FRA/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/GBR/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/GBR/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/GRC/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/GRC/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/HRV/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/HRV/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/HUN/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/HUN/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/IDN/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/IDN/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/IND/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/IND/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/IRL/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/IRL/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/ITA/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/ITA/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/JPN/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/JPN/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/KOR/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/KOR/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/MEX/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/MEX/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/MRN/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/MRN/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/MYS/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/MYS/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/NGA/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/NGA/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/NLD/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/NLD/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/NOR/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/NOR/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/PHL/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/PHL/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/POL/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/POL/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/PRT/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/PRT/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/RUS/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/RUS/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/SAU/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/SAU/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/SGP/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/SGP/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/SUI/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/SUI/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/SVN/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/SVN/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/SWE/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/SWE/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/TUN/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/TUN/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/TUR/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/TUR/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/USA/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/USA/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/ZAF/FirstName.csv +501 -0
- golemorph-1.1.0/golemorph/data/ZAF/Surname.csv +501 -0
- golemorph-1.1.0/golemorph/data/manifest.yaml +996 -0
- golemorph-1.1.0/golemorph/loader.py +201 -0
- golemorph-1.1.0/golemorph/models.py +130 -0
- golemorph-1.1.0/golemorph/persona.py +371 -0
- golemorph-1.1.0/golemorph/sampler.py +54 -0
- golemorph-1.1.0/golemorph.egg-info/PKG-INFO +197 -0
- golemorph-1.1.0/golemorph.egg-info/SOURCES.txt +110 -0
- golemorph-1.1.0/golemorph.egg-info/dependency_links.txt +1 -0
- golemorph-1.1.0/golemorph.egg-info/entry_points.txt +2 -0
- golemorph-1.1.0/golemorph.egg-info/requires.txt +2 -0
- golemorph-1.1.0/golemorph.egg-info/top_level.txt +1 -0
- golemorph-1.1.0/pyproject.toml +34 -0
- golemorph-1.1.0/setup.cfg +4 -0
- golemorph-1.1.0/tests/test_cli.py +189 -0
- golemorph-1.1.0/tests/test_loader.py +133 -0
- golemorph-1.1.0/tests/test_persona.py +55 -0
golemorph-1.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HiitCat
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
golemorph-1.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: golemorph
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Complete, coherent synthetic personas for authorized red team spearphishing campaigns: name, email, phone, backstory.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/HiitCat/Golemorph
|
|
7
|
+
Project-URL: Repository, https://github.com/HiitCat/Golemorph
|
|
8
|
+
Project-URL: Issues, https://github.com/HiitCat/Golemorph/issues
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: PyYAML>=6.0
|
|
13
|
+
Requires-Dist: rich>=13.0
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
<div align="center">
|
|
17
|
+
|
|
18
|
+
<img src="https://raw.githubusercontent.com/HiitCat/Golemorph/main/docs/assets/golemorph.png" alt="Golemorph logo" width="160">
|
|
19
|
+
|
|
20
|
+
# Golemorph
|
|
21
|
+
|
|
22
|
+
**Coherent synthetic personas for authorized red-team spearphishing engagements.**
|
|
23
|
+
|
|
24
|
+
Every identity is internally consistent - name, email, phone, age, city and
|
|
25
|
+
role all follow the chosen origin, across 45 locales.
|
|
26
|
+
|
|
27
|
+
[](https://pypi.org/project/golemorph/)
|
|
28
|
+
[](https://www.python.org/)
|
|
29
|
+
[](LICENSE)
|
|
30
|
+
[](https://x.com/hitc_at)
|
|
31
|
+
|
|
32
|
+
<img src="https://raw.githubusercontent.com/HiitCat/Golemorph/main/docs/assets/demo.png" alt="Golemorph generating a batch of French personas" width="900">
|
|
33
|
+
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- **Coherent identities** - name, email, phone, age, city and role all match
|
|
39
|
+
the origin's language, dial code and conventions.
|
|
40
|
+
- **45 locales**, grouped by region, every name romanized to Latin (accents
|
|
41
|
+
kept) so emails stay readable.
|
|
42
|
+
- **Credible by default** - frequency-weighted sampling bounded to a percentile
|
|
43
|
+
band that skips both "John Doe" names and odd, unplaceable ones.
|
|
44
|
+
- **Realistic emails** - several local-part layouts (`first.last`, `jdupont`,
|
|
45
|
+
`dupont.jean`, ...) over region-appropriate domains.
|
|
46
|
+
- **Ready-to-use exports** - a rich color table for the terminal, plus `csv`,
|
|
47
|
+
`json`, and a GoPhish group-import CSV.
|
|
48
|
+
- **Reproducible** - `--seed` makes any campaign repeatable.
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
Requires Python 3.11+.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pipx install golemorph
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### From source
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
62
|
+
pip install -e .
|
|
63
|
+
|
|
64
|
+
# optional: tests + data regeneration
|
|
65
|
+
pip install -r requirements-dev.txt
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or run it straight from the repo root without installing (needs its runtime
|
|
69
|
+
deps, PyYAML and rich - `pip install -r requirements.txt`):
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
python3 -m golemorph --help
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Quick start
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# 45 supported origins, grouped by region (filter: europe|americas|africa|asia)
|
|
79
|
+
golemorph --list-origins
|
|
80
|
+
golemorph --list-origins europe
|
|
81
|
+
|
|
82
|
+
# Five Russian personas, full JSON records
|
|
83
|
+
golemorph -o RUS -n 5 --format json
|
|
84
|
+
|
|
85
|
+
# 100 French personas, gophish CSV format saved in custom file
|
|
86
|
+
golemorph -o FRA -n 100 -f gophish --output targets.csv
|
|
87
|
+
|
|
88
|
+
# 50 personas, no repeated name, reproducible
|
|
89
|
+
golemorph -o DEU -n 50 --unique --seed 7
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
With no arguments, Golemorph prints a single American persona (the default
|
|
93
|
+
origin is `USA`) as a table. The default `name` format renders a rich,
|
|
94
|
+
color table - name, age, birth year, city, language, role, phone, email and
|
|
95
|
+
the `commonality` score; use `-f csv`/`json` for machine-readable output.
|
|
96
|
+
|
|
97
|
+
## Options
|
|
98
|
+
|
|
99
|
+
| Flag | Meaning | Default |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `-o, --origin CODE` | Origin code (see `--list-origins`) | `USA` |
|
|
102
|
+
| `-n, --count N` | Personas to generate | `1` |
|
|
103
|
+
| `-u, --unique [PART]` | No repeats across the run: `full` whole name (default), `first` given names, `last` surnames | off |
|
|
104
|
+
| `-g, --gender G` | `Male` or `Female`; unset draws per-name gender from the dataset | mixed |
|
|
105
|
+
| `-f, --format FMT` | `name` (rich table), `csv`, `json`, or `gophish` | `name` |
|
|
106
|
+
| `--unweighted` | Uniform sampling instead of frequency-weighted | weighted |
|
|
107
|
+
| `--min-common PCT` | Exclude names rarer than this percentile (`0` keeps all) | `10` |
|
|
108
|
+
| `--max-common PCT` | Exclude names more common than this percentile, avoiding the "John Doe" effect (`100` keeps all) | `95` |
|
|
109
|
+
| `--seed N` | Reproducible output | random |
|
|
110
|
+
| `--output FILE` | Write output to a file instead of stdout | stdout |
|
|
111
|
+
| `--list-origins [GROUP]` | Print the origins table and exit; optional `GROUP` filter (`all`, `europe`, `americas`, `africa`, `asia`) | - |
|
|
112
|
+
|
|
113
|
+
## Output formats
|
|
114
|
+
|
|
115
|
+
- **`name`** (default): a rich, color table of the headline fields - name,
|
|
116
|
+
age, birth year, city, language, role, phone, email and `commonality`.
|
|
117
|
+
Color and box drawing are dropped automatically when the output is piped or
|
|
118
|
+
redirected.
|
|
119
|
+
- **`csv`**: one row per persona with the full record - `id`, `gender`,
|
|
120
|
+
`first_name`, `last_name`, `origin_code`, `origin_label`, `nationality`,
|
|
121
|
+
`language`, `name_order`, `birth_year`, `age`, `email`, `phone`, `city`,
|
|
122
|
+
`role`, `first_name_percentile`, `last_name_percentile`, `commonality`,
|
|
123
|
+
`full_name`.
|
|
124
|
+
- **`json`**: one JSON array of full records, same fields as the CSV.
|
|
125
|
+
- **`gophish`**: the GoPhish group-import template - `First Name, Last Name,
|
|
126
|
+
Email, Position` rows (Position carries the persona's role), ready to import
|
|
127
|
+
directly into a GoPhish target group.
|
|
128
|
+
|
|
129
|
+
## Origins
|
|
130
|
+
|
|
131
|
+
Golemorph ships 45 origins across Europe, the Americas, Africa, the Middle
|
|
132
|
+
East and Asia-Pacific:
|
|
133
|
+
|
|
134
|
+
| Group | Origins |
|
|
135
|
+
|---|---|
|
|
136
|
+
| Europe | ๐ฆ๐น `AUT`, ๐ง๐ช `BEL`, ๐ง๐ฌ `BGR`, ๐จ๐ฟ `CZE`, ๐ฉ๐ช `DEU`, ๐ฉ๐ฐ `DNK`, ๐ช๐ธ `ESP`, ๐ซ๐ฎ `FIN`, ๐ซ๐ท `FRA`, ๐ฌ๐ง `GBR`, ๐ฌ๐ท `GRC`, ๐ญ๐ท `HRV`, ๐ญ๐บ `HUN`, ๐ฎ๐ช `IRL`, ๐ฎ๐น `ITA`, ๐ณ๐ฑ `NLD`, ๐ณ๐ด `NOR`, ๐ต๐ฑ `POL`, ๐ต๐น `PRT`, ๐ท๐บ `RUS`, ๐จ๐ญ `SUI`, ๐ธ๐ฎ `SVN`, ๐ธ๐ช `SWE`, ๐น๐ท `TUR` |
|
|
137
|
+
| Americas | ๐ฆ๐ท `ARG`, ๐ง๐ท `BRA`, ๐จ๐ฆ `CAN`, ๐จ๐ด `COL`, ๐ฒ๐ฝ `MEX`, ๐บ๐ธ `USA` |
|
|
138
|
+
| Africa / MENA | ๐ฉ๐ฟ `ALG`, ๐ช๐ฌ `EGY`, ๐ฒ๐ฆ `MRN`, ๐ณ๐ฌ `NGA`, ๐ธ๐ฆ `SAU`, ๐น๐ณ `TUN`, ๐ฟ๐ฆ `ZAF` |
|
|
139
|
+
| Asia-Pacific | ๐จ๐ณ `CHN`, ๐ฎ๐ฉ `IDN`, ๐ฎ๐ณ `IND`, ๐ฏ๐ต `JPN`, ๐ฐ๐ท `KOR`, ๐ฒ๐พ `MYS`, ๐ต๐ญ `PHL`, ๐ธ๐ฌ `SGP` |
|
|
140
|
+
|
|
141
|
+
`--list-origins` prints them as color tables, one per region, and takes an
|
|
142
|
+
optional group filter:
|
|
143
|
+
|
|
144
|
+
<p align="center">
|
|
145
|
+
<img src="https://raw.githubusercontent.com/HiitCat/Golemorph/main/docs/assets/origins_europe.png" alt="golemorph --list-origins europe" width="420">
|
|
146
|
+
</p>
|
|
147
|
+
|
|
148
|
+
Full table with language, name order, dial code and nationality wording:
|
|
149
|
+
[`docs/origins.md`](docs/origins.md).
|
|
150
|
+
|
|
151
|
+
## Data
|
|
152
|
+
|
|
153
|
+
Names are sampled (by default with replacement; see `--unique`) from per-origin
|
|
154
|
+
CSVs generated from
|
|
155
|
+
[names-dataset 3.3.1](https://github.com/typpo/names-dataset) (Facebook,
|
|
156
|
+
~533M users) by `scripts/generate_name_data.py`:
|
|
157
|
+
|
|
158
|
+
- **Frequency-weighted** sampling, with long-tail counts decayed along a
|
|
159
|
+
Zipf-like curve so mid-tier names are drawn far more often than raw counts
|
|
160
|
+
alone would suggest. `--unweighted` switches to uniform.
|
|
161
|
+
- **Credible band**: by default the draw is bounded to a percentile band
|
|
162
|
+
(`--min-common` / `--max-common`) that drops both the most common names,
|
|
163
|
+
which read as "John Doe" placeholders, and the rarest, least placeable ones.
|
|
164
|
+
- **Unique names**: `--unique` rejects and redraws duplicates so a chosen part
|
|
165
|
+
of the name never repeats across the run - `full` (whole name, the default),
|
|
166
|
+
`first` (given names) or `last` (surnames). `--unique full` still lets a
|
|
167
|
+
first name or surname recur in a different pairing; `first`/`last` keep that
|
|
168
|
+
one field strictly distinct. Errors if the pool is too small.
|
|
169
|
+
- **Gendered** first names; Russian surnames carry romanized gendered forms
|
|
170
|
+
(`Ivanov`/`Ivanova`), and a female persona never draws the male form.
|
|
171
|
+
- **Latin-only** spellings: every locale keeps its romanized names (accents
|
|
172
|
+
allowed, e.g. `Josรฉ`, `Mรผller`), so native-script entries (Arabic, Cyrillic,
|
|
173
|
+
Greek, CJK, Hangul) are dropped in favour of their Latin forms and emails
|
|
174
|
+
stay name-based.
|
|
175
|
+
- Surnames drop standalone name *particles* (`El`, `Ben`, `Da`, `De`, `Von`,
|
|
176
|
+
`Ait`, ...) that the source stores as entries in their own right because it
|
|
177
|
+
splits compound names on the space; genuine short surnames that collide with
|
|
178
|
+
those tokens (`Le`, `Do`, `Du`, `Ba`, `Das`, `Dal`) are kept.
|
|
179
|
+
- Emails mix several realistic local-part layouts (`first.last`, `firstlast`,
|
|
180
|
+
`jdupont`, `j.dupont`, `jean.d`, `dupont.jean`, with an optional numeric
|
|
181
|
+
suffix) over a regional domain; phone numbers follow the origin's dial code
|
|
182
|
+
and mobile prefix.
|
|
183
|
+
|
|
184
|
+
Regenerate the shipped data. The source dataset ships inside the
|
|
185
|
+
[`names-dataset`](https://pypi.org/project/names-dataset/) package (a dev
|
|
186
|
+
dependency), so there is nothing to download by hand and it works on any OS:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
pip install -r requirements-dev.txt # installs names-dataset + PyYAML
|
|
190
|
+
python3 scripts/generate_name_data.py
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Tests
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
python3 -m pytest tests/
|
|
197
|
+
```
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="https://raw.githubusercontent.com/HiitCat/Golemorph/main/docs/assets/golemorph.png" alt="Golemorph logo" width="160">
|
|
4
|
+
|
|
5
|
+
# Golemorph
|
|
6
|
+
|
|
7
|
+
**Coherent synthetic personas for authorized red-team spearphishing engagements.**
|
|
8
|
+
|
|
9
|
+
Every identity is internally consistent - name, email, phone, age, city and
|
|
10
|
+
role all follow the chosen origin, across 45 locales.
|
|
11
|
+
|
|
12
|
+
[](https://pypi.org/project/golemorph/)
|
|
13
|
+
[](https://www.python.org/)
|
|
14
|
+
[](LICENSE)
|
|
15
|
+
[](https://x.com/hitc_at)
|
|
16
|
+
|
|
17
|
+
<img src="https://raw.githubusercontent.com/HiitCat/Golemorph/main/docs/assets/demo.png" alt="Golemorph generating a batch of French personas" width="900">
|
|
18
|
+
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- **Coherent identities** - name, email, phone, age, city and role all match
|
|
24
|
+
the origin's language, dial code and conventions.
|
|
25
|
+
- **45 locales**, grouped by region, every name romanized to Latin (accents
|
|
26
|
+
kept) so emails stay readable.
|
|
27
|
+
- **Credible by default** - frequency-weighted sampling bounded to a percentile
|
|
28
|
+
band that skips both "John Doe" names and odd, unplaceable ones.
|
|
29
|
+
- **Realistic emails** - several local-part layouts (`first.last`, `jdupont`,
|
|
30
|
+
`dupont.jean`, ...) over region-appropriate domains.
|
|
31
|
+
- **Ready-to-use exports** - a rich color table for the terminal, plus `csv`,
|
|
32
|
+
`json`, and a GoPhish group-import CSV.
|
|
33
|
+
- **Reproducible** - `--seed` makes any campaign repeatable.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
Requires Python 3.11+.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pipx install golemorph
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### From source
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
47
|
+
pip install -e .
|
|
48
|
+
|
|
49
|
+
# optional: tests + data regeneration
|
|
50
|
+
pip install -r requirements-dev.txt
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or run it straight from the repo root without installing (needs its runtime
|
|
54
|
+
deps, PyYAML and rich - `pip install -r requirements.txt`):
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
python3 -m golemorph --help
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quick start
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# 45 supported origins, grouped by region (filter: europe|americas|africa|asia)
|
|
64
|
+
golemorph --list-origins
|
|
65
|
+
golemorph --list-origins europe
|
|
66
|
+
|
|
67
|
+
# Five Russian personas, full JSON records
|
|
68
|
+
golemorph -o RUS -n 5 --format json
|
|
69
|
+
|
|
70
|
+
# 100 French personas, gophish CSV format saved in custom file
|
|
71
|
+
golemorph -o FRA -n 100 -f gophish --output targets.csv
|
|
72
|
+
|
|
73
|
+
# 50 personas, no repeated name, reproducible
|
|
74
|
+
golemorph -o DEU -n 50 --unique --seed 7
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
With no arguments, Golemorph prints a single American persona (the default
|
|
78
|
+
origin is `USA`) as a table. The default `name` format renders a rich,
|
|
79
|
+
color table - name, age, birth year, city, language, role, phone, email and
|
|
80
|
+
the `commonality` score; use `-f csv`/`json` for machine-readable output.
|
|
81
|
+
|
|
82
|
+
## Options
|
|
83
|
+
|
|
84
|
+
| Flag | Meaning | Default |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `-o, --origin CODE` | Origin code (see `--list-origins`) | `USA` |
|
|
87
|
+
| `-n, --count N` | Personas to generate | `1` |
|
|
88
|
+
| `-u, --unique [PART]` | No repeats across the run: `full` whole name (default), `first` given names, `last` surnames | off |
|
|
89
|
+
| `-g, --gender G` | `Male` or `Female`; unset draws per-name gender from the dataset | mixed |
|
|
90
|
+
| `-f, --format FMT` | `name` (rich table), `csv`, `json`, or `gophish` | `name` |
|
|
91
|
+
| `--unweighted` | Uniform sampling instead of frequency-weighted | weighted |
|
|
92
|
+
| `--min-common PCT` | Exclude names rarer than this percentile (`0` keeps all) | `10` |
|
|
93
|
+
| `--max-common PCT` | Exclude names more common than this percentile, avoiding the "John Doe" effect (`100` keeps all) | `95` |
|
|
94
|
+
| `--seed N` | Reproducible output | random |
|
|
95
|
+
| `--output FILE` | Write output to a file instead of stdout | stdout |
|
|
96
|
+
| `--list-origins [GROUP]` | Print the origins table and exit; optional `GROUP` filter (`all`, `europe`, `americas`, `africa`, `asia`) | - |
|
|
97
|
+
|
|
98
|
+
## Output formats
|
|
99
|
+
|
|
100
|
+
- **`name`** (default): a rich, color table of the headline fields - name,
|
|
101
|
+
age, birth year, city, language, role, phone, email and `commonality`.
|
|
102
|
+
Color and box drawing are dropped automatically when the output is piped or
|
|
103
|
+
redirected.
|
|
104
|
+
- **`csv`**: one row per persona with the full record - `id`, `gender`,
|
|
105
|
+
`first_name`, `last_name`, `origin_code`, `origin_label`, `nationality`,
|
|
106
|
+
`language`, `name_order`, `birth_year`, `age`, `email`, `phone`, `city`,
|
|
107
|
+
`role`, `first_name_percentile`, `last_name_percentile`, `commonality`,
|
|
108
|
+
`full_name`.
|
|
109
|
+
- **`json`**: one JSON array of full records, same fields as the CSV.
|
|
110
|
+
- **`gophish`**: the GoPhish group-import template - `First Name, Last Name,
|
|
111
|
+
Email, Position` rows (Position carries the persona's role), ready to import
|
|
112
|
+
directly into a GoPhish target group.
|
|
113
|
+
|
|
114
|
+
## Origins
|
|
115
|
+
|
|
116
|
+
Golemorph ships 45 origins across Europe, the Americas, Africa, the Middle
|
|
117
|
+
East and Asia-Pacific:
|
|
118
|
+
|
|
119
|
+
| Group | Origins |
|
|
120
|
+
|---|---|
|
|
121
|
+
| Europe | ๐ฆ๐น `AUT`, ๐ง๐ช `BEL`, ๐ง๐ฌ `BGR`, ๐จ๐ฟ `CZE`, ๐ฉ๐ช `DEU`, ๐ฉ๐ฐ `DNK`, ๐ช๐ธ `ESP`, ๐ซ๐ฎ `FIN`, ๐ซ๐ท `FRA`, ๐ฌ๐ง `GBR`, ๐ฌ๐ท `GRC`, ๐ญ๐ท `HRV`, ๐ญ๐บ `HUN`, ๐ฎ๐ช `IRL`, ๐ฎ๐น `ITA`, ๐ณ๐ฑ `NLD`, ๐ณ๐ด `NOR`, ๐ต๐ฑ `POL`, ๐ต๐น `PRT`, ๐ท๐บ `RUS`, ๐จ๐ญ `SUI`, ๐ธ๐ฎ `SVN`, ๐ธ๐ช `SWE`, ๐น๐ท `TUR` |
|
|
122
|
+
| Americas | ๐ฆ๐ท `ARG`, ๐ง๐ท `BRA`, ๐จ๐ฆ `CAN`, ๐จ๐ด `COL`, ๐ฒ๐ฝ `MEX`, ๐บ๐ธ `USA` |
|
|
123
|
+
| Africa / MENA | ๐ฉ๐ฟ `ALG`, ๐ช๐ฌ `EGY`, ๐ฒ๐ฆ `MRN`, ๐ณ๐ฌ `NGA`, ๐ธ๐ฆ `SAU`, ๐น๐ณ `TUN`, ๐ฟ๐ฆ `ZAF` |
|
|
124
|
+
| Asia-Pacific | ๐จ๐ณ `CHN`, ๐ฎ๐ฉ `IDN`, ๐ฎ๐ณ `IND`, ๐ฏ๐ต `JPN`, ๐ฐ๐ท `KOR`, ๐ฒ๐พ `MYS`, ๐ต๐ญ `PHL`, ๐ธ๐ฌ `SGP` |
|
|
125
|
+
|
|
126
|
+
`--list-origins` prints them as color tables, one per region, and takes an
|
|
127
|
+
optional group filter:
|
|
128
|
+
|
|
129
|
+
<p align="center">
|
|
130
|
+
<img src="https://raw.githubusercontent.com/HiitCat/Golemorph/main/docs/assets/origins_europe.png" alt="golemorph --list-origins europe" width="420">
|
|
131
|
+
</p>
|
|
132
|
+
|
|
133
|
+
Full table with language, name order, dial code and nationality wording:
|
|
134
|
+
[`docs/origins.md`](docs/origins.md).
|
|
135
|
+
|
|
136
|
+
## Data
|
|
137
|
+
|
|
138
|
+
Names are sampled (by default with replacement; see `--unique`) from per-origin
|
|
139
|
+
CSVs generated from
|
|
140
|
+
[names-dataset 3.3.1](https://github.com/typpo/names-dataset) (Facebook,
|
|
141
|
+
~533M users) by `scripts/generate_name_data.py`:
|
|
142
|
+
|
|
143
|
+
- **Frequency-weighted** sampling, with long-tail counts decayed along a
|
|
144
|
+
Zipf-like curve so mid-tier names are drawn far more often than raw counts
|
|
145
|
+
alone would suggest. `--unweighted` switches to uniform.
|
|
146
|
+
- **Credible band**: by default the draw is bounded to a percentile band
|
|
147
|
+
(`--min-common` / `--max-common`) that drops both the most common names,
|
|
148
|
+
which read as "John Doe" placeholders, and the rarest, least placeable ones.
|
|
149
|
+
- **Unique names**: `--unique` rejects and redraws duplicates so a chosen part
|
|
150
|
+
of the name never repeats across the run - `full` (whole name, the default),
|
|
151
|
+
`first` (given names) or `last` (surnames). `--unique full` still lets a
|
|
152
|
+
first name or surname recur in a different pairing; `first`/`last` keep that
|
|
153
|
+
one field strictly distinct. Errors if the pool is too small.
|
|
154
|
+
- **Gendered** first names; Russian surnames carry romanized gendered forms
|
|
155
|
+
(`Ivanov`/`Ivanova`), and a female persona never draws the male form.
|
|
156
|
+
- **Latin-only** spellings: every locale keeps its romanized names (accents
|
|
157
|
+
allowed, e.g. `Josรฉ`, `Mรผller`), so native-script entries (Arabic, Cyrillic,
|
|
158
|
+
Greek, CJK, Hangul) are dropped in favour of their Latin forms and emails
|
|
159
|
+
stay name-based.
|
|
160
|
+
- Surnames drop standalone name *particles* (`El`, `Ben`, `Da`, `De`, `Von`,
|
|
161
|
+
`Ait`, ...) that the source stores as entries in their own right because it
|
|
162
|
+
splits compound names on the space; genuine short surnames that collide with
|
|
163
|
+
those tokens (`Le`, `Do`, `Du`, `Ba`, `Das`, `Dal`) are kept.
|
|
164
|
+
- Emails mix several realistic local-part layouts (`first.last`, `firstlast`,
|
|
165
|
+
`jdupont`, `j.dupont`, `jean.d`, `dupont.jean`, with an optional numeric
|
|
166
|
+
suffix) over a regional domain; phone numbers follow the origin's dial code
|
|
167
|
+
and mobile prefix.
|
|
168
|
+
|
|
169
|
+
Regenerate the shipped data. The source dataset ships inside the
|
|
170
|
+
[`names-dataset`](https://pypi.org/project/names-dataset/) package (a dev
|
|
171
|
+
dependency), so there is nothing to download by hand and it works on any OS:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
pip install -r requirements-dev.txt # installs names-dataset + PyYAML
|
|
175
|
+
python3 scripts/generate_name_data.py
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Tests
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
python3 -m pytest tests/
|
|
182
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Golemorph: complete, coherent synthetic personas for authorized red team
|
|
2
|
+
spearphishing campaigns.
|
|
3
|
+
|
|
4
|
+
The public surface is deliberately small: load an origin, generate personas,
|
|
5
|
+
hand them to GoPhish. Everything locale-specific (name order, dial code, email
|
|
6
|
+
domains, cities, roles) is data in `data/manifest.yaml`, never code, so
|
|
7
|
+
adding a locale never means touching this package.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .loader import load_origin, load_first_names, load_surnames, origins
|
|
11
|
+
from .models import Gender, NameEntry, OriginProfile, Persona
|
|
12
|
+
from .persona import generate_personas
|
|
13
|
+
from .sampler import NameSampler
|
|
14
|
+
|
|
15
|
+
__version__ = "2.0.0"
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"Gender",
|
|
19
|
+
"NameEntry",
|
|
20
|
+
"OriginProfile",
|
|
21
|
+
"Persona",
|
|
22
|
+
"NameSampler",
|
|
23
|
+
"generate_personas",
|
|
24
|
+
"load_first_names",
|
|
25
|
+
"load_origin",
|
|
26
|
+
"load_surnames",
|
|
27
|
+
"origins",
|
|
28
|
+
"__version__",
|
|
29
|
+
]
|