
Chanjing Credentials Guard
- 55 installs
- 18 repo stars
- Updated March 28, 2026
- chanjing-ai/chan-skills
Guides users to configure and validate local Chanjing AK/SK credentials and token status using local commands only.
About
Helps configure and check Chanjing API keys and access tokens through local scripts without ever asking for secrets in chat. A developer uses it to set up or recover Chanjing credentials before calling other Chanjing skills.
- Configures/validates Chanjing AK/SK and token via local scripts only
- Never requests secrets in chat; opens login page locally
Chanjing Credentials Guard by the numbers
- 55 all-time installs (skills.sh)
- Ranked #1,270 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/chanjing-ai/chan-skills --skill chanjing-credentials-guardAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 55 |
|---|---|
| repo stars | ★ 18 |
| Last updated | March 28, 2026 |
| Repository | chanjing-ai/chan-skills ↗ |
What it does
Guides users to configure and validate local Chanjing AK/SK credentials and token status using local commands only.
Files
Chanjing Credentials Guard
功能说明
仅通过本地命令引导用户配置/校验蝉镜 AK/SK 与 Token,打开登录页;不在对话中索取密钥。可配合其它 Chanjing 技能使用。
运行依赖
- python3 与
scripts/chanjing_config.py、scripts/open_login_page.py、scripts/chanjing_get_token.py等
环境变量与机器可读声明
- 环境变量键名与说明:`manifest.yaml`(
environment段)及本文 - 变量、写盘路径与权限:`manifest.yaml`
使用命令
- ClawHub(slug 以注册表为准):
clawhub run chanjing-credentials-guard - 本仓库:
python skills/chanjing-credentials-guard/scripts/chanjing_config.py --status
---
When to Run
1. When user asks to configure/get Chanjing keys (AK/SK): use this skill to guide local setup. 2. When credentials are missing/invalid before a Chanjing API call: use this skill to recover local config.
This skill is a local credential guide, not a cross-skill runtime dependency.
Execution Flow
1. Check if local AK/SK exists
└─ No → Run open_login_page.py (open login in browser) → Ask user to run local config command
└─ Yes → Continue
2. Check if local Token exists and is not expired
└─ No → Call API to request/refresh Token → Save
└─ Yes → Continue
3. Prompt user to continue target actionCredential Storage (AK/SK read from config file)
AK/SK and Token are read from the same config file. Path and format follow the script `scripts/chanjing_config.py` in this skill.
- Path:
~/.chanjing/credentials.json(目录由 `CHANJING_OPENAPI_CREDENTIALS_DIR` 覆盖,兼容 `CHANJING_CONFIG_DIR`) - Format:
{
"app_id": "Your Access Key",
"secret_key": "Your Secret Key",
"access_token": "Optional, auto-generated",
"expire_in": 1721289220
}expire_in is a Unix timestamp. Token is valid for about 24 hours; refresh 5 minutes before expiry.
When AK/SK Is Missing
When local app_id or secret_key is missing:
1. Open login page: Run the open_login_page.py script to open the Chanjing sign-in page in the default browser (https://www.chanjing.cc/openapi/login). 2. Require local setup command after the user obtains keys:
- Show command only; user runs it locally in terminal.
3. Do not request secrets in chat:
- Never ask user to paste AK/SK in conversation.
- Never echo or store AK/SK in chat summaries.
4. After setting:
- Ask user to run status check and then proceed to target action.
Commands to set AK/SK (use either):
python scripts/chanjing_config.py --ak <your_app_id> --sk <your_secret_key>
python skills/chanjing-credentials-guard/scripts/chanjing_config.py --ak <your_app_id> --sk <your_secret_key>To open the login page manually: python skills/chanjing-credentials-guard/scripts/open_login_page.py
Guide When User Wants to Generate Keys
When the user clearly wants to generate chanjing keys, get keys, or configure AK/SK, follow this flow:
Step 1: Check if already configured
Check if local AK/SK already exists (read ~/.chanjing/credentials.json for non-empty app_id and secret_key, or run python skills/chanjing-credentials-guard/scripts/chanjing_config.py --status).
Step 2: Branch on result
- If already configured: ask whether user wants to overwrite local config.
- If yes, run guide steps.
- If no, stop.
- If not configured: Run the “Guide steps” below directly.
Guide steps (when not configured or user confirmed re-apply)
1. Run `open_login_page.py` to open the Chanjing login page in the default browser. 2. Explain the page flow clearly:
- New users are registered automatically and the current page will display
App IDandSecret Keywith copy buttons. - Existing users may be redirected to the console; tell them to open the left-side API 密钥 page to view or reset keys.
3. Ask user to run local command to configure AK/SK:
python skills/chanjing-credentials-guard/scripts/chanjing_config.py --ak <your_app_id> --sk <your_secret_key>4. Secret handling rule:
- Do not ask user to paste AK/SK in chat.
- If user shares secret in chat anyway, remind them to rotate keys and continue with local-command-only flow.
5. After setting:
- Run status check:
python skills/chanjing-credentials-guard/scripts/chanjing_config.py --status
- Then proceed to target Chanjing action.
Token API (see chanjing-openapi.yaml)
POST https://open-api.chanjing.cc/open/v1/access_token
Content-Type: application/jsonRequest body:
{
"app_id": "{{app_id}}",
"secret_key": "{{secret_key}}"
}Response (success code: 0):
{
"code": 0,
"msg": "success",
"data": {
"access_token": "xxx",
"expire_in": 1721289220
}
}expire_in: Unix timestamp for token expiry- If
code !== 0, AK/SK is invalid or the request failed
Validation Logic
1. AK/SK: Read from config (path/format above, per chanjing_config.py); ensure app_id and secret_key are non-empty. 2. Token: Ensure access_token exists and expire_in > current_time + 300 (refresh 5 minutes early). 3. Token refresh: Call the API above and write returned access_token and expire_in back to the file.
Shortcut: Run python skills/chanjing-credentials-guard/scripts/chanjing_get_token.py; on success it prints access_token, on failure it prints guidance.
Security Boundary
- This skill only handles local credential guidance.
- It does not require install hooks or elevated/system-wide privileges.
- It should not automatically execute unrelated skills.
- It should not accept AK/SK via chat content.
Shell Config
| Script | Description |
|---|---|
open_login_page.py | Opens the Chanjing login page and explains how new/existing users obtain AK/SK |
chanjing_config.py | Set or view AK/SK and Token status |
chanjing_get_token.py | Print a valid access_token to stdout (or guidance on failure) |
# Open login page (also runs automatically when AK/SK is missing)
python skills/chanjing-credentials-guard/scripts/open_login_page.py
# Set AK/SK manually
python skills/chanjing-credentials-guard/scripts/chanjing_config.py --ak <app_id> --sk <secret_key>
# View status
python skills/chanjing-credentials-guard/scripts/chanjing_config.py --statusWith Other Skills
- Other Chanjing skills may use the same local config path/format, but should keep their own runtime auth logic.
- Guard can be used as an optional setup helper when users explicitly ask for credential guidance.
Reference
- reference.md: API and storage format details
- chanjing-openapi.yaml:
/access_token,dto.OpenAccessTokenReq,dto.OpenAccessTokenResp
# 合规:根目录 合规规则.md §1–§2
name: chanjing-credentials-guard
version: 0.1.0
vendor: chanjing
runtime:
interpreter: python3
dependencies: []
env:
required: []
optional:
- CHANJING_OPENAPI_CREDENTIALS_DIR
- CHANJING_OPENAPI_BASE_URL
permissions:
network_mode: allowlist
allowed_hosts:
- open-api.chanjing.cc
- www.chanjing.cc
filesystem:
read_roots:
- "${WORKSPACE_ROOT}"
- "${SKILL_DIR}"
- "${CHANJING_OPENAPI_CREDENTIALS_DIR}"
write_roots:
- "${WORKSPACE_ROOT}"
- "${CHANJING_OPENAPI_CREDENTIALS_DIR}"
allowed_commands:
- python3
schemaVersion: 1
skill:
id: chanjing-credentials-guard
author: chan-skills
category: 凭证与安全
tags:
- credentials
- AKSK
- Chanjing
- 蝉镜
- 本地配置
summary: >-
本地引导配置/校验蝉镜 AK/SK 与 Token;不通过对话索取密钥;可打开登录页。
skillDoc: SKILL.md
environment:
variables:
- name: CHANJING_OPENAPI_CREDENTIALS_DIR
required: false
description: 存放 credentials.json 的目录(兼容 CHANJING_CONFIG_DIR),默认 ~/.chanjing
- name: CHANJING_OPENAPI_BASE_URL
required: false
description: 刷新 Token 等 API 基址(兼容 CHANJING_API_BASE),默认 https://open-api.chanjing.cc
credentials:
model: credentials_json
defaultPath: "~/.chanjing/credentials.json"
directoryEnv: CHANJING_OPENAPI_CREDENTIALS_DIR
fileName: credentials.json
sensitiveFields:
- app_id
- secret_key
- access_token
- expire_in
persistAccessTokenOnDisk: true
primaryEnvIntentionallyOmitted: true
doNotCommitToVcs:
- credentials.json
clientPermissions:
network:
httpsOutbound: true
documentedHosts:
- open-api.chanjing.cc
- www.chanjing.cc
filesystem:
read:
- "${CHANJING_OPENAPI_CREDENTIALS_DIR or CHANJING_CONFIG_DIR or ~/.chanjing}/credentials.json"
write:
- "${CHANJING_OPENAPI_CREDENTIALS_DIR or CHANJING_CONFIG_DIR or ~/.chanjing}/credentials.json"
- "${CHANJING_OPENAPI_CREDENTIALS_DIR or CHANJING_CONFIG_DIR or ~/.chanjing}/"
browser:
mayOpenForAuth: true
documentedHosts:
- www.chanjing.cc
subprocess:
allowedPatterns:
- python3
userContent: {}
metadata:
openclaw:
homepage: https://doc.chanjing.cc
agentPolicy:
alwaysSkill: false
modifiesOtherSkillsOrGlobalAgent: false
Credentials Guard Reference
API (chanjing-openapi.yaml)
Get Access Token
| Item | Value |
|---|---|
| Method | POST |
| URL | https://open-api.chanjing.cc/open/v1/access_token |
| Content-Type | application/json |
Request body (dto.OpenAccessTokenReq):
| Field | Type | Required | Description |
|---|---|---|---|
| app_id | string | Yes | Access Key (AK) |
| secret_key | string | Yes | Secret Key (SK) |
Response (success code=0):
| Field | Type | Description |
|---|---|---|
| code | int | 0 = success |
| msg | string | Message |
| data.access_token | string | API credential |
| data.expire_in | int | Unix timestamp, token expiry |
Error codes:
| code | Description |
|---|---|
| 0 | Success |
| 400 | Invalid parameter format |
| 40000 | Parameter error |
| 50000 | Internal error |
Credential storage format
AK/SK are read from a config file. Path and format follow `scripts/chanjing_config.py` (see CONFIG_DIR, CONFIG_FILE, and read_config() in that script).
File path: ~/.chanjing/credentials.json (default; override with env CHANJING_CONFIG_DIR)
{
"app_id": "Access Key",
"secret_key": "Secret Key",
"access_token": "From API, optional",
"expire_in": 1721289220
}expire_inis a Unix timestamp- Token is valid for about 24 hours
- Refresh 5 minutes (300 seconds) before expiry
Environment variables
| Variable | Description | Default |
|---|---|---|
| CHANJING_CONFIG_DIR | Credentials directory | ~/.chanjing |
| CHANJING_API_BASE | API base URL | https://open-api.chanjing.cc |
Login and obtaining keys
- Sign up / Login: https://www.chanjing.cc/openapi/login
- Docs: https://doc.chanjing.cc
#!/usr/bin/env python3
"""
蝉镜凭证配置脚本。AK/SK 与 Token 均从本脚本定义的配置文件中读写。
配置文件: CONFIG_DIR/credentials.json(默认 ~/.chanjing;目录由 CHANJING_OPENAPI_CREDENTIALS_DIR 或旧名 CHANJING_CONFIG_DIR 覆盖)。
用法: python chanjing_config.py --ak <app_id> --sk <secret_key> | --status | --help
"""
import argparse
import json
import os
import sys
from pathlib import Path
def credentials_config_dir() -> Path:
raw = os.environ.get("CHANJING_OPENAPI_CREDENTIALS_DIR") or os.environ.get("CHANJING_CONFIG_DIR")
return Path(raw).expanduser() if raw else Path.home() / ".chanjing"
CONFIG_DIR = credentials_config_dir()
CONFIG_FILE = CONFIG_DIR / "credentials.json"
LOGIN_URL = "https://www.chanjing.cc/openapi/login"
DOC_URL = "https://doc.chanjing.cc"
def ensure_config_dir():
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
try:
os.chmod(CONFIG_DIR, 0o700)
except OSError:
pass
def read_config():
if CONFIG_FILE.exists():
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
return json.load(f)
return {}
def write_config(data):
ensure_config_dir()
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
try:
os.chmod(CONFIG_FILE, 0o600)
except OSError:
pass
def show_status():
ensure_config_dir()
if not CONFIG_FILE.exists():
print("状态: 未配置")
print()
print("请先设置 AK/SK:")
print(" python skills/chanjing-credentials-guard/scripts/chanjing_config.py --ak <你的app_id> --sk <你的secret_key>")
print()
print("获取秘钥:", LOGIN_URL)
return 1
data = read_config()
has_ak = bool(data.get("app_id"))
has_sk = bool(data.get("secret_key"))
print("配置路径:", CONFIG_FILE)
print("AK (app_id):", "已配置" if has_ak else "未配置")
print("SK (secret_key):", "已配置" if has_sk else "未配置")
if not has_ak or not has_sk:
print()
print("请完成 AK/SK 配置:")
print(" python skills/chanjing-credentials-guard/scripts/chanjing_config.py --ak <你的app_id> --sk <你的secret_key>")
print()
print("获取秘钥:", LOGIN_URL)
return 1
if data.get("access_token") and data.get("expire_in") is not None:
import time
try:
expire_in = int(data["expire_in"])
now = int(time.time())
if expire_in > now + 300:
from datetime import datetime
try:
dt = datetime.fromtimestamp(expire_in)
print("Token: 有效 (过期时间:", dt.strftime("%Y-%m-%d %H:%M:%S"), ")")
except Exception:
print("Token: 有效 (过期时间戳:", expire_in, ")")
else:
print("Token: 已过期或即将过期,下次调用 API 时将自动刷新")
except (ValueError, TypeError):
print("Token: 已过期或即将过期,下次调用 API 时将自动刷新")
else:
print("Token: 未获取,下次调用 API 时将自动申请")
return 0
def set_credentials(ak, sk):
data = read_config()
data["app_id"] = ak
data["secret_key"] = sk
write_config(data)
print("凭证已保存到", CONFIG_FILE)
print()
print("验证配置: python skills/chanjing-credentials-guard/scripts/chanjing_config.py --status")
def main():
parser = argparse.ArgumentParser(
description="蝉镜凭证配置工具",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="存储位置: %s\n获取秘钥: %s\n文档: %s" % (CONFIG_FILE, LOGIN_URL, DOC_URL),
)
parser.add_argument("--ak", help="Access Key (app_id)")
parser.add_argument("--sk", help="Secret Key (secret_key)")
parser.add_argument("--status", "-s", action="store_true", help="查看配置状态")
args = parser.parse_args()
if args.status:
sys.exit(show_status())
if args.ak and args.sk:
set_credentials(args.ak, args.sk)
return
if args.ak or args.sk:
print("错误: 必须同时提供 --ak 和 --sk", file=sys.stderr)
parser.print_help()
sys.exit(1)
# 默认显示状态
sys.exit(show_status())
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
获取有效的 access_token。
AK/SK 从与 chanjing_config.py 相同的配置文件中读取(CONFIG_DIR/credentials.json,见 chanjing_config.py)。
若无 AK/SK 则输出引导信息并退出;若 Token 过期则自动申请并保存。
用法: python chanjing_get_token.py
输出: 成功时打印 access_token 到 stdout;失败时打印错误到 stderr 并 exit 1
"""
import json
import os
import sys
import urllib.request
from pathlib import Path
_DEFAULT_OPENAPI_BASE = "https://open-api.chanjing.cc"
def credentials_config_dir() -> Path:
raw = os.environ.get("CHANJING_OPENAPI_CREDENTIALS_DIR") or os.environ.get("CHANJING_CONFIG_DIR")
return Path(raw).expanduser() if raw else Path.home() / ".chanjing"
def openapi_base_url() -> str:
return (
os.environ.get("CHANJING_OPENAPI_BASE_URL")
or os.environ.get("CHANJING_API_BASE")
or _DEFAULT_OPENAPI_BASE
).rstrip("/")
CONFIG_DIR = credentials_config_dir()
CONFIG_FILE = CONFIG_DIR / "credentials.json"
API_URL = openapi_base_url() + "/open/v1/access_token"
BUFFER_SECONDS = 300 # 提前 5 分钟刷新
def _run_open_login_page():
"""在默认浏览器打开蝉镜登录页。"""
try:
import webbrowser
webbrowser.open("https://www.chanjing.cc/openapi/login")
except Exception:
try:
import webbrowser
webbrowser.open("https://www.chanjing.cc/openapi/login")
except Exception:
pass
def read_config():
if CONFIG_FILE.exists():
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
return json.load(f)
return {}
def write_config(data):
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
try:
os.chmod(CONFIG_FILE, 0o600)
except OSError:
pass
def fetch_token(app_id, secret_key):
req = urllib.request.Request(
API_URL,
data=json.dumps({"app_id": app_id, "secret_key": secret_key}).encode("utf-8"),
headers={"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req, timeout=30) as resp:
body = json.loads(resp.read().decode("utf-8"))
return body
def main():
data = read_config()
app_id = data.get("app_id", "").strip()
secret_key = data.get("secret_key", "").strip()
if not app_id or not secret_key:
_run_open_login_page()
print(
"已在浏览器打开蝉镜登录/注册页。",
"获取秘钥后请执行:",
" python skills/chanjing-credentials-guard/scripts/chanjing_config.py --ak <你的app_id> --sk <你的secret_key>",
"设置完毕后请重新执行您之前的操作或当前命令。",
sep="\n",
file=sys.stderr,
)
sys.exit(1)
import time
now = int(time.time())
token = data.get("access_token")
expire_in = data.get("expire_in")
try:
expire_in = int(expire_in) if expire_in is not None else 0
except (ValueError, TypeError):
expire_in = 0
if token and expire_in > now + BUFFER_SECONDS:
print(token)
return 0
# 申请新 Token
try:
resp = fetch_token(app_id, secret_key)
except Exception as e:
print(f"请求 Token 失败: {e}", file=sys.stderr)
sys.exit(1)
if resp.get("code") != 0:
msg = resp.get("msg", "未知错误")
print(f"获取 Token 失败 (code={resp.get('code')}): {msg}", file=sys.stderr)
sys.exit(1)
d = resp.get("data", {})
new_token = d.get("access_token")
new_expire = d.get("expire_in")
if not new_token:
print("API 返回无 access_token", file=sys.stderr)
sys.exit(1)
data["access_token"] = new_token
data["expire_in"] = new_expire
write_config(data)
print(new_token)
return 0
if __name__ == "__main__":
sys.exit(main())
#!/usr/bin/env python3
"""
打开蝉镜 AK/SK 注册/登录页面。无参数直接运行即可。
用法: python open_login_page.py 或 python skills/chanjing-credentials-guard/scripts/open_login_page.py
"""
import platform
import shutil
import subprocess
import webbrowser
LOGIN_URL = "https://www.chanjing.cc/openapi/login"
def _run_open_command(command, method_name):
try:
subprocess.run(
command,
check=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE,
text=True,
)
return True, method_name, None
except subprocess.CalledProcessError as exc:
error = (exc.stderr or "").strip() or str(exc)
return False, method_name, error
except OSError as exc:
return False, method_name, str(exc)
def _command_attempts():
system = platform.system()
if system == "Darwin":
return [(["open", LOGIN_URL], "macOS open")]
if system == "Windows":
return [(["cmd", "/c", "start", "", LOGIN_URL], "Windows start")]
attempts = []
if shutil.which("xdg-open"):
attempts.append((["xdg-open", LOGIN_URL], "xdg-open"))
if shutil.which("gio"):
attempts.append((["gio", "open", LOGIN_URL], "gio open"))
return attempts
def open_login_url():
errors = []
for command, method_name in _command_attempts():
opened, used_method, error = _run_open_command(command, method_name)
if opened:
return True, used_method, None
errors.append(f"{used_method}: {error}")
try:
opened = webbrowser.open(LOGIN_URL, new=2)
if opened:
return True, "python webbrowser", None
errors.append("python webbrowser: webbrowser.open() 返回 False")
except Exception as exc:
errors.append(f"python webbrowser: {exc}")
if not errors:
errors.append("当前系统没有可用的浏览器启动命令")
return False, None, ";".join(errors)
def main():
opened, method, error = open_login_url()
if opened:
print("已在浏览器打开蝉镜登录页。")
print(f"打开方式:{method}")
else:
print("未能自动打开浏览器,请手动访问下面的地址:")
print(f" {LOGIN_URL}")
print()
print(f"失败原因:{error}")
print()
print("获取 AK/SK 的方式:")
print("1. 新用户:注册成功后,当前页面会直接展示 App ID 和 Secret Key,可点击复制按钮。")
print("2. 老用户:登录后如果进入控制台,请在左侧菜单进入“API 密钥”页面查看或重置密钥。")
print()
print("拿到秘钥后请执行:")
print(" python skills/chanjing-credentials-guard/scripts/chanjing_config.py --ak <你的app_id> --sk <你的secret_key>")
print("设置完毕后请重新执行您之前的操作。")
if __name__ == "__main__":
main()