codexunlimit 0.1.0-web.12 → 0.1.0-web.13

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.
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Cài một gói trên Windows hoặc macOS, mở trình duyệt và bắt đầu sử dụng. Hỗ trợ Node.js 22 từ 22.15.0, hoặc Node.js 24 trở lên.
4
4
 
5
+ ## Sửa thông báo kích hoạt · web.13
6
+
7
+ Phân biệt lỗi ngày giờ máy khách, phản hồi xác thực không hợp lệ và key bị máy chủ từ chối. Khi admin đã ghi nhận kích hoạt nhưng máy khách báo lỗi ngày giờ, đồng bộ lại ngày giờ tự động, khởi động lại Codex Unlimit và nhập lại cùng key. Kích hoạt lại trên cùng thiết bị với dữ liệu ứng dụng còn nguyên không tăng số thiết bị hay tính lại thời hạn. Key hết hạn hoặc bị thu hồi thật vẫn bị chặn.
8
+
5
9
  ## Cài và mở
6
10
 
7
11
  Mở PowerShell (Windows) hoặc Terminal (macOS/Linux). Cài và mở bằng hai dòng:
@@ -8,11 +8,11 @@ import {hash,publicText,signProof,verifyEnvelope} from './protocol.mjs';
8
8
  import {boundedJson} from './io.mjs';
9
9
  class RelayError extends Error{constructor(status,code){super(code);this.status=status;this.code=code;}}
10
10
  const TERMINAL_DENIALS=new Set(['license_invalid_or_expired','device_revoked','activation_invalid','device_already_bound_or_revoked']);
11
- const LOCAL_DENIALS=new Set(['activation_required','license_signature_invalid','clock_rollback_detected','license_invalid_or_expired','license_revoked']);
11
+ const LOCAL_DENIALS=new Set(['activation_required','license_signature_invalid','clock_rollback_detected','license_clock_skew','license_invalid_or_expired','license_revoked']);
12
12
  function serviceError(code,status=503,retryAfter=1){const error=new RelayError(status,code);error.transient=true;error.authoritative=false;error.retryAfter=retryAfter;return error;}
13
13
  function normalizeFailure(error){
14
14
  const code=typeof error?.code==='string'?error.code:error?.message;
15
- if(code==='license_lease_expired')return serviceError(code,503,error?.retryAfter??1);
15
+ if(code==='license_lease_expired'||code==='license_response_invalid')return serviceError(code,503,error?.retryAfter??1);
16
16
  if(error?.transient||error?.status>=500||error?.status===429||['license_server_unavailable','license_response_invalid','license_service_busy','try_later','ingress_rate_limit','ingress_busy','ingress_capacity'].includes(code))return serviceError(code==='license_service_busy'||error?.status===429?'license_service_busy':'license_server_unavailable',error?.status===429?429:503,error?.retryAfter??1);
17
17
  if(TERMINAL_DENIALS.has(code)||LOCAL_DENIALS.has(code)){const failure=new RelayError(403,code);failure.authoritative=error?.authoritative!==false;return failure;}
18
18
  return serviceError('license_server_unavailable');
@@ -71,11 +71,14 @@ export class LicenseClient {
71
71
  check(envelope=this.state.get('license.lease'),feature='desktop',{allowExpired=false}={}){
72
72
  let claims;try{claims=verifyEnvelope(envelope,this.publicKey);}catch{throw Error('license_signature_invalid');}
73
73
  const now=this.now(),last=this.state.get('license.clock')??0;
74
+ // Local validation cannot establish that the issuer revoked or expired a key.
75
+ if(!claims||claims.kind!=='tdh-relay-lease-v1'||claims.product!=='tdh-relay'||claims.deviceId!==this.device.deviceId||
76
+ typeof claims.licenseId!=='string'||!claims.licenseId||typeof claims.activationId!=='string'||!claims.activationId||
77
+ claims.keyHash!==hash(this.device.publicKey)||!Array.isArray(claims.features)||!claims.features.includes(feature)||!Number.isSafeInteger(claims.licenseExpiresAt)||
78
+ !Number.isSafeInteger(claims.issuedAt)||!Number.isSafeInteger(claims.expiresAt)||
79
+ claims.expiresAt<=claims.issuedAt||claims.expiresAt>claims.issuedAt+600000||claims.expiresAt>claims.licenseExpiresAt)throw serviceError('license_response_invalid');
74
80
  if(now<last-30000||now<this.wallStart+performance.now()-this.monotonicStart-30000)throw Error('clock_rollback_detected');
75
- if(claims.kind!=='tdh-relay-lease-v1'||claims.product!=='tdh-relay'||claims.deviceId!==this.device.deviceId||
76
- claims.keyHash!==hash(this.device.publicKey)||!Array.isArray(claims.features)||!claims.features.includes(feature)||!Number.isFinite(claims.licenseExpiresAt)||
77
- !Number.isFinite(claims.issuedAt)||!Number.isFinite(claims.expiresAt)||claims.issuedAt>now+60000||
78
- claims.expiresAt<=claims.issuedAt||claims.expiresAt>claims.issuedAt+600000||claims.expiresAt>claims.licenseExpiresAt)throw Error('license_invalid_or_expired');
81
+ if(claims.issuedAt>now+60000)throw Error('license_clock_skew');
79
82
  if(!allowExpired&&claims.expiresAt<=now)throw serviceError('license_lease_expired');
80
83
  if(now>last+10000)this.state.set('license.clock',now);
81
84
  return claims;
@@ -86,7 +89,7 @@ export class LicenseClient {
86
89
  return {challengeId:challenge.id,proof:signProof(action,challenge.nonce,this.device.deviceId,this.device.publicKey,this.device.privateKey)};
87
90
  }
88
91
  save(response){
89
- const claims=this.check(response.lease);
92
+ let claims;try{claims=this.check(response?.lease??null);}catch(error){error.authoritative=false;throw error;}
90
93
  this.state.transaction(()=>{this.state.set('license.lease',response.lease);this.state.set('license.activation',claims.activationId);this.state.set('license.denied',false);});
91
94
  this.nextAttempt=0;this.lastFailure=null;this.failures=0;return claims;
92
95
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexunlimit",
3
- "version": "0.1.0-web.12",
3
+ "version": "0.1.0-web.13",
4
4
  "private": false,
5
5
  "description": "Codex Unlimit — trò chuyện và quản lý kết nối trên máy của bạn",
6
6
  "type": "module",
package/product.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const VERSION='0.1.0-web.12';
1
+ export const VERSION='0.1.0-web.13';
2
2
  export const PRODUCT='codexunlimit-connector';
3
3
  export const DEFAULT_PORT=18457;
4
4
  export const LICENSE_ORIGIN='https://codexunlimit.tudonghoa.me';
package/web/messages.js CHANGED
@@ -22,8 +22,10 @@ export const errors={
22
22
  request_integrity_failed:'Yêu cầu chưa được xác thực. Cập nhật Codex Unlimit rồi thử lại.',
23
23
  license_server_unavailable:'Chưa liên lạc được máy chủ kiểm tra key. Kiểm tra mạng rồi chọn Kiểm tra thời hạn.',
24
24
  license_service_busy:'Máy chủ kiểm tra key đang bận. Chờ vài giây rồi thử lại; đây không phải thông báo key hết hạn.',
25
- license_lease_expired:'Phiên xác thực tạm thời đã hết hạn. Chọn Kiểm tra thời hạn để lấy phiên mới; nếu lặp lại, kiểm tra ngày giờ trên máy.',
26
- license_invalid_or_expired:'Key đã hết hạn hoặc bị thu hồi. Liên hệ nơi cấp key.',
25
+ license_lease_expired:'Phiên xác thực tạm thời đã hết hạn. Thử lại thao tác; nếu lỗi lặp lại, đồng bộ ngày giờ rồi khởi động lại ứng dụng.',
26
+ license_clock_skew:'Ngày giờ trên máy chưa khớp với máy chủ xác thực. Bật đồng bộ ngày giờ tự động, khởi động lại Codex Unlimit rồi thử lại thao tác.',
27
+ license_response_invalid:'Thông tin xác thực nhận được không hợp lệ. Thử lại thao tác; nếu vẫn lỗi, cập nhật Codex Unlimit và liên hệ hỗ trợ.',
28
+ license_invalid_or_expired:'Key không hợp lệ, đã hết hạn hoặc bị thu hồi. Kiểm tra lại mã hoặc liên hệ nơi cấp key.',
27
29
  license_revoked:'Key đã bị thu hồi. Liên hệ nơi cấp key.',
28
30
  device_limit_reached:'Key đã đủ số máy được phép dùng. Mở trang khách hàng để kiểm tra thiết bị.',
29
31
  device_revoked:'Thiết bị này đã bị thu hồi quyền sử dụng. Liên hệ nơi cấp key.',
@@ -61,6 +63,6 @@ export const errors={
61
63
  startup_update_failed:'Chưa cập nhật được tùy chọn khởi động cùng Windows. Kiểm tra quyền ghi thư mục Startup rồi thử lại.',
62
64
  tray_unavailable:'Chưa mở được biểu tượng khay Windows. Bạn vẫn có thể mở và tắt ứng dụng tại trang này.',
63
65
  invalid_input:'Thông tin gửi chưa hợp lệ. Tải lại trang rồi thử lại.',
64
- clock_rollback_detected:'Giờ trên máy chưa khớp. Bật đồng bộ ngày giờ của hệ điều hành rồi kiểm tra thời hạn lại.',
66
+ clock_rollback_detected:'Ngày giờ trên máy đã thay đổi hoặc chưa khớp. Bật đồng bộ ngày giờ tự động, khởi động lại Codex Unlimit rồi thử lại thao tác.',
65
67
  license_signature_invalid:'Chưa xác minh được thông tin key. Chọn Kiểm tra thời hạn; nếu vẫn lỗi hãy cập nhật ứng dụng.'
66
68
  };