Node.js SDK
@signox/sdk — Node.js(서버·CLI·Electron)용 공식 SDK입니다. 런타임 의존성 0개, Node 14 이상을 지원합니다.
- 모든 서버 응답을 제품 Ed25519 공개키로 서명검증한 뒤에만 신뢰합니다(위변조·재생 방어).
- 기기 식별자(hwid)는 SDK가 내부에서 자동 생성합니다 — 호출자가 다룰 필요가 없습니다.
- 판정은 예외가 아니라
LicenseResult.code값으로 전달됩니다. 네트워크 실패(NETWORK_ERROR)와 무효 판정은 항상 구분됩니다. - 온라인 검증 캐시 + 완전 오프라인(
.lic) 검증을 모두 지원합니다.
npm install @signox/sdk빠른 시작
섹션 제목: “빠른 시작”import { SignoxClient } from '@signox/sdk';
const client = new SignoxClient({ // 제품 공개키(SPKI PEM) — 반드시 앱에 임베드하세요. 아래 "공개키 임베드" 참고. productPublicKey: `-----BEGIN PUBLIC KEY-----MCowBQYDK2Vw...-----END PUBLIC KEY-----`, // baseUrl 기본값: https://api.signox.kr});
const licenseKey = 'S4K2MB-7IWQ3F-9XG5JN-P2QN8R-QW3ZOD-8T7V2X';
// 1) 디바이스 활성화 (최초 1회 / 기기 이동 시) — 멱등const activated = await client.activate(licenseKey, { name: '홍길동의 노트북' });if (!activated.valid) { console.error('활성화 실패:', activated.code); // 예: DEVICE_LIMIT_REACHED, VM_NOT_ALLOWED}
// 2) 검증 (앱 시작 시 / 주기적으로)const result = await client.validate(licenseKey);if (result.valid) { // VALID 또는 IN_GRACE_PERIOD console.log('기능:', result.features); // { pro_export: true, max_seats: 10, ... }} else if (result.code === 'NETWORK_ERROR') { // 서버 도달 실패 + 유효 캐시 없음 — 무효 판정이 아님. 재시도 또는 유예 UX 처리} else { console.warn('무효:', result.code); // EXPIRED, REVOKED, DEVICE_NOT_ACTIVATED ...}activate는 현재 플랫폼과 hwid, 이상 신호(vm 등)를 자동으로 수집해 전송합니다.
API
섹션 제목: “API”client.validate(licenseKey) // 검증 (성공 응답은 자동 캐시)client.activate(licenseKey, { name?, platform? }) // 디바이스 활성화client.deactivate(licenseKey) // 디바이스 해제(슬롯 반환)client.heartbeat(licenseKey) // 생존 신호(텔레메트리)client.reportUsage(licenseKey, feature, value?) // 메터링 사용량 보고(기본 1)client.requestOfflineFile(licenseKey) // .lic 발급 → result.file.contentclient.validateOffline(licContent) // 완전 로컬 검증(동기)client.getHwid() // 진단용 hwid 조회판정 결과 (LicenseResult)
섹션 제목: “판정 결과 (LicenseResult)”| 필드 | 설명 |
|---|---|
valid |
VALID·IN_GRACE_PERIOD 두 코드에서만 true |
code |
판정 코드 (아래) |
features |
정책 기능값 맵 (bool/int/string) — 무효 시 {} |
license / product |
라이센스·제품 정보 (검증 성공 시) |
device |
activate 성공 시 디바이스 정보 |
usage |
reportUsage 시 메터링 사용량 |
file |
requestOfflineFile 성공 시 .lic 내용 |
fromCache |
네트워크 없이 유효 캐시에서 반환됨 |
stale |
네트워크 실패로 만료된 캐시에서 폴백됨 |
판정 코드
섹션 제목: “판정 코드”- 상태:
VALID,IN_GRACE_PERIOD,EXPIRED,SUSPENDED,REVOKED - 요청/디바이스:
NOT_FOUND,PRODUCT_INACTIVE,HWID_REQUIRED,DEVICE_NOT_ACTIVATED,DEVICE_LIMIT_REACHED,VM_NOT_ALLOWED,FEATURE_NOT_FOUND,USAGE_LIMIT_REACHED - SDK 로컬 판정:
SIGNATURE_INVALID,NONCE_MISMATCH,OFFLINE_FILE_INVALID,HWID_MISMATCH,NETWORK_ERROR
코드별 의미와 권장 UX는 온라인 활성화 가이드를 참고하세요.
설정 (SignoxConfig)
섹션 제목: “설정 (SignoxConfig)”| 옵션 | 기본값 | 설명 |
|---|---|---|
productPublicKey |
(필수) | 제품 공개키 SPKI PEM |
baseUrl |
https://api.signox.kr |
API 베이스 URL |
timeout |
10000 |
요청 타임아웃(ms) |
cacheDir |
(없음) | 지정 시 서명된 응답 원문을 디스크에 캐시. 미지정 시 인메모리만 |
tsToleranceSec |
300 |
응답 meta.ts 허용 시계 오차(초) |
offlineGraceDays |
7 |
네트워크 실패 시 stale 캐시 폴백 허용 일수 — 캐시 저장 시점 기준. 0 = 폴백 안 함 |
캐시와 오프라인 폴백
섹션 제목: “캐시와 오프라인 폴백”validate성공 응답은 서버가 준cache.ttl동안 신뢰되어 재검증을 생략합니다.- 캐시에는 서명된 응답 원문(raw) 만 저장되며 읽을 때마다 서명을 재검증합니다(변조 방어).
- 네트워크 실패 시
offlineGraceDays이내의 캐시가 있으면 그 판정으로 폴백하며stale이true가 됩니다. cacheDir를 지정하면 프로세스 재시작 후에도 캐시가 유지됩니다.
오프라인 검증 (.lic)
섹션 제목: “오프라인 검증 (.lic)”인터넷이 없는 기기는 포털·대시보드에서 .lic 파일을 발급받아 사용합니다. 전체 플로우는 오프라인 활성화를 참고하세요.
// 온라인 기기에서 발급받아 저장const res = await client.requestOfflineFile(licenseKey);if (res.file) fs.writeFileSync('license.lic', res.file.content);
// 오프라인 기기에서 검증 (네트워크 없음)const offline = client.validateOffline(fs.readFileSync('license.lic', 'utf8'));if (offline.valid) { // VALID(무기한/유효) 또는 IN_GRACE_PERIOD}공개키 임베드 (중요)
섹션 제목: “공개키 임베드 (중요)”productPublicKey는 반드시 앱 바이너리에 임베드하세요. SDK는 제품 공개키를 서버에서 조회하는 기능을 의도적으로 제공하지 않습니다 — 공개키를 네트워크로 받으면 중간자가 자신의 키로 바꿔치기해 위조 응답을 유효하게 만들 수 있기 때문입니다. 서명 검증의 신뢰 뿌리가 이 임베드된 공개키 하나이므로, 여기에 조회·설정 주입 같은 우회로를 두지 마세요. 비밀키는 절대 클라이언트에 넣지 마세요(서명은 서버 전용).