콘텐츠로 이동

Node.js SDK

@signox/sdk — Node.js(서버·CLI·Electron)용 공식 SDK입니다. 런타임 의존성 0개, Node 14 이상을 지원합니다.

  • 모든 서버 응답을 제품 Ed25519 공개키로 서명검증한 뒤에만 신뢰합니다(위변조·재생 방어).
  • 기기 식별자(hwid)는 SDK가 내부에서 자동 생성합니다 — 호출자가 다룰 필요가 없습니다.
  • 판정은 예외가 아니라 LicenseResult.code 값으로 전달됩니다. 네트워크 실패(NETWORK_ERROR)와 무효 판정은 항상 구분됩니다.
  • 온라인 검증 캐시 + 완전 오프라인(.lic) 검증을 모두 지원합니다.
Terminal window
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 등)를 자동으로 수집해 전송합니다.

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.content
client.validateOffline(licContent) // 완전 로컬 검증(동기)
client.getHwid() // 진단용 hwid 조회
필드 설명
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는 온라인 활성화 가이드를 참고하세요.

옵션 기본값 설명
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 이내의 캐시가 있으면 그 판정으로 폴백하며 staletrue가 됩니다.
  • cacheDir를 지정하면 프로세스 재시작 후에도 캐시가 유지됩니다.

인터넷이 없는 기기는 포털·대시보드에서 .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는 제품 공개키를 서버에서 조회하는 기능을 의도적으로 제공하지 않습니다 — 공개키를 네트워크로 받으면 중간자가 자신의 키로 바꿔치기해 위조 응답을 유효하게 만들 수 있기 때문입니다. 서명 검증의 신뢰 뿌리가 이 임베드된 공개키 하나이므로, 여기에 조회·설정 주입 같은 우회로를 두지 마세요. 비밀키는 절대 클라이언트에 넣지 마세요(서명은 서버 전용).