diff --git a/README.md b/README.md index ba73f1d..90f20d8 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ A small Python standard-library HTTP service with a static web UI for address/pr - `server.py` — HTTP server and API proxy/fallback logic. - `index.html` — browser UI; calls the local `/api/v1/dz` endpoint. - `.env.example` — documented optional runtime environment variables. +- `scripts/gen.py` — existing standalone helper for querying the fallback provider. +- `docs/migration-inventory.md` — migrated content and cutover notes. - `deploy/address-tool.service.example` — example systemd unit for this repository layout. ## Requirements diff --git a/docs/migration-inventory.md b/docs/migration-inventory.md new file mode 100644 index 0000000..cace4c4 --- /dev/null +++ b/docs/migration-inventory.md @@ -0,0 +1,28 @@ +# Existing service content migration inventory + +Source service directory: `/root/.openclaw/workspace/address_tool` +Active systemd unit: `address-tool.service` + +## Migrated into this repository + +- `server.py`: API server, request throttling, FakeNameGenerator integration and fallback provider logic. Repository copy uses a directory-relative web root and environment-only API key configuration. +- `index.html`: active browser UI served by the API server. +- `scripts/gen.py`: existing standalone CLI helper that calls the fallback address API. +- `.env.example`: names and defaults for runtime configuration; contains no credentials. +- `deploy/address-tool.service.example`: example unit for a future migration. + +## Intentionally not copied into Git + +- `server.py.bak-*`, `index.html.bak-*`: historical snapshots, not runtime inputs. The full source directory was preserved in a separate backup before extraction. +- `__pycache__/`: generated Python bytecode. +- Runtime credentials: kept only in an ignored local `.env` file (mode 600) when available from the existing source. Never commit it. + +## Current deployment status + +The existing systemd unit still runs `/root/.openclaw/workspace/address_tool/server.py` on port 18990. This migration does not stop, restart, or repoint that service. A later cutover must first test the repository copy and configure its environment file and service account. + +## External runtime dependencies + +- Optional FakeNameGenerator API, configured with `FNG_API_KEY`. +- Fallback API `https://www.meiguodizhi.com/api/v1/dz`. +- Cap.js widget/CDN and CAPTCHA endpoint referenced by `index.html`. diff --git a/scripts/gen.py b/scripts/gen.py new file mode 100755 index 0000000..f52a0c3 --- /dev/null +++ b/scripts/gen.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +import datetime +import json +import random +import re +import sys +import urllib.request + +API_URL = "https://www.meiguodizhi.com/api/v1/dz" + +WORD_POOL = [ + "sunshine", "ocean", "river", "mountain", "shadow", "forest", "galaxy", + "silver", "breeze", "whisper", "crystal", "journey", "falcon", "amber", + "meadow", "harbor", "sunset", "thunder", "frost", "velvet", "aurora", + "beacon", "canyon", "echo", "flame", "horizon", "island", "lunar", + "mystic", "nebula", "phoenix", "radiant", "stellar", "summit", "vortex", + "winter", "spring", "summer", "timber", "willow", "valley" +] + +def generate_password_hint(): + # 随机 2~3 个英文单词直接拼接为纯英文字符串(无符号) + count = 3 if random.random() > 0.5 else 2 + chosen = random.sample(WORD_POOL, count) + return "".join(w.capitalize() for w in chosen) + +def generate_birthday_18_to_19(): + # 年龄大于 18 且小于 20(即 18 岁 ~ 19 岁之间) + # 格式:dd/mm/yyyy + today = datetime.date.today() + # 满 18 岁但未满 20 岁 + max_birth = today - datetime.timedelta(days=int(18.01 * 365.25)) + min_birth = today - datetime.timedelta(days=int(19.99 * 365.25)) + + total_days = (max_birth - min_birth).days + random_days = random.randint(0, max_days if (max_days := total_days) > 0 else 0) + bdate = min_birth + datetime.timedelta(days=random_days) + return bdate.strftime("%d/%m/%Y") + +def get_address(city="Virginia Beach"): + headers = { + "Content-Type": "application/json", + "Referer": "https://www.meiguodizhi.com/", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" + } + payload = json.dumps({ + "city": city, + "path": "/", + "method": "refresh" + }).encode("utf-8") + + try: + req = urllib.request.Request(API_URL, data=payload, headers=headers) + with urllib.request.urlopen(req, timeout=10) as resp: + data = json.loads(resp.read().decode("utf-8")) + if data.get("status") == "ok": + return data.get("address", {}) + except Exception as e: + sys.stderr.write(f"请求失败: {e}\n") + + return None + +def main(): + city = sys.argv[1] if len(sys.argv) > 1 else "Virginia Beach" + addr = get_address(city) + + if not addr: + print("获取失败,请重试。") + sys.exit(1) + + name = addr.get("Full_Name", "").strip() + street = re.sub(r"\s+", " ", addr.get("Address", "").strip()) + city_name = addr.get("City", "").strip() + state = addr.get("State", "").strip() + zip_code = addr.get("Zip_Code", "").strip() + phone = addr.get("Telephone", "").strip() + + full_addr = f"{street}, {city_name}, {state} {zip_code}" + pwd_hint = generate_password_hint() + birthday = generate_birthday_18_to_19() + + print(f"全名:{name}") + print(f"完整地址:{full_addr}") + print(f"电话号码:{phone}") + print(f"密码提示:{pwd_hint}") + print(f"生日:{birthday}") + +if __name__ == "__main__": + main()