sesame-kit 0.4.0

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.
Files changed (170) hide show
  1. package/LICENSE +26 -0
  2. package/LICENSE.biz3 +21 -0
  3. package/README.ja.md +225 -0
  4. package/README.md +222 -0
  5. package/bin/sesame.js +8 -0
  6. package/clients/js/sesame-client.mjs +208 -0
  7. package/clients/python/pyproject.toml +5 -0
  8. package/clients/python/sesame_client.py +323 -0
  9. package/clients/python/setup.cfg +11 -0
  10. package/docs/architecture.ja.md +132 -0
  11. package/docs/architecture.md +105 -0
  12. package/docs/commands.ja.md +316 -0
  13. package/docs/commands.md +308 -0
  14. package/docs/library.ja.md +152 -0
  15. package/docs/library.md +152 -0
  16. package/docs/migration.ja.md +13 -0
  17. package/docs/migration.md +13 -0
  18. package/package.json +114 -0
  19. package/src/access.js +375 -0
  20. package/src/account.js +36 -0
  21. package/src/auth.js +248 -0
  22. package/src/ble/devicemodel.js +164 -0
  23. package/src/ble/index.js +185 -0
  24. package/src/ble/protocol.js +319 -0
  25. package/src/ble/session.js +235 -0
  26. package/src/ble/transport.js +279 -0
  27. package/src/cli/access.js +373 -0
  28. package/src/cli/company.js +104 -0
  29. package/src/cli/iot.js +400 -0
  30. package/src/cli/org.js +788 -0
  31. package/src/cli/presetir.js +188 -0
  32. package/src/cli/schedule.js +83 -0
  33. package/src/cli/serve.js +308 -0
  34. package/src/cli.js +1815 -0
  35. package/src/client.js +957 -0
  36. package/src/company.js +147 -0
  37. package/src/config.js +575 -0
  38. package/src/crypto.js +162 -0
  39. package/src/devices.js +228 -0
  40. package/src/index.js +55 -0
  41. package/src/iot.js +513 -0
  42. package/src/ir.js +341 -0
  43. package/src/itemcodes.js +29 -0
  44. package/src/lock.js +194 -0
  45. package/src/org.js +803 -0
  46. package/src/paths.js +30 -0
  47. package/src/presetir.js +525 -0
  48. package/src/prompts.js +74 -0
  49. package/src/schedule.js +108 -0
  50. package/src/serve/daemon.js +251 -0
  51. package/src/serve/framing/grpc.js +145 -0
  52. package/src/serve/framing/http.js +144 -0
  53. package/src/serve/framing/ndjson.js +75 -0
  54. package/src/serve/framing/socket.js +73 -0
  55. package/src/serve/framing/stdio.js +28 -0
  56. package/src/serve/framing/token.js +36 -0
  57. package/src/serve/framing/ws.js +56 -0
  58. package/src/serve/grpc-methods.generated.json +378 -0
  59. package/src/serve/jsonrpc.js +164 -0
  60. package/src/serve/registry.js +226 -0
  61. package/src/serve/rpc-params.generated.json +1746 -0
  62. package/src/serve/sesame.proto +470 -0
  63. package/src/session-ui.js +181 -0
  64. package/src/sharekey.js +130 -0
  65. package/src/tokens.js +53 -0
  66. package/src/transport.js +634 -0
  67. package/src/util.js +26 -0
  68. package/types/access.d.ts +193 -0
  69. package/types/access.d.ts.map +1 -0
  70. package/types/account.d.ts +13 -0
  71. package/types/account.d.ts.map +1 -0
  72. package/types/auth.d.ts +80 -0
  73. package/types/auth.d.ts.map +1 -0
  74. package/types/ble/devicemodel.d.ts +212 -0
  75. package/types/ble/devicemodel.d.ts.map +1 -0
  76. package/types/ble/index.d.ts +160 -0
  77. package/types/ble/index.d.ts.map +1 -0
  78. package/types/ble/protocol.d.ts +201 -0
  79. package/types/ble/protocol.d.ts.map +1 -0
  80. package/types/ble/session.d.ts +129 -0
  81. package/types/ble/session.d.ts.map +1 -0
  82. package/types/ble/transport.d.ts +67 -0
  83. package/types/ble/transport.d.ts.map +1 -0
  84. package/types/cli/access.d.ts +6 -0
  85. package/types/cli/access.d.ts.map +1 -0
  86. package/types/cli/company.d.ts +6 -0
  87. package/types/cli/company.d.ts.map +1 -0
  88. package/types/cli/iot.d.ts +6 -0
  89. package/types/cli/iot.d.ts.map +1 -0
  90. package/types/cli/org.d.ts +6 -0
  91. package/types/cli/org.d.ts.map +1 -0
  92. package/types/cli/presetir.d.ts +6 -0
  93. package/types/cli/presetir.d.ts.map +1 -0
  94. package/types/cli/schedule.d.ts +6 -0
  95. package/types/cli/schedule.d.ts.map +1 -0
  96. package/types/cli/serve.d.ts +2 -0
  97. package/types/cli/serve.d.ts.map +1 -0
  98. package/types/cli.d.ts +2 -0
  99. package/types/cli.d.ts.map +1 -0
  100. package/types/client.d.ts +463 -0
  101. package/types/client.d.ts.map +1 -0
  102. package/types/company.d.ts +94 -0
  103. package/types/company.d.ts.map +1 -0
  104. package/types/config.d.ts +111 -0
  105. package/types/config.d.ts.map +1 -0
  106. package/types/crypto.d.ts +61 -0
  107. package/types/crypto.d.ts.map +1 -0
  108. package/types/devices.d.ts +116 -0
  109. package/types/devices.d.ts.map +1 -0
  110. package/types/index.d.ts +23 -0
  111. package/types/index.d.ts.map +1 -0
  112. package/types/iot.d.ts +312 -0
  113. package/types/iot.d.ts.map +1 -0
  114. package/types/ir.d.ts +147 -0
  115. package/types/ir.d.ts.map +1 -0
  116. package/types/itemcodes.d.ts +21 -0
  117. package/types/itemcodes.d.ts.map +1 -0
  118. package/types/lock.d.ts +89 -0
  119. package/types/lock.d.ts.map +1 -0
  120. package/types/org.d.ts +468 -0
  121. package/types/org.d.ts.map +1 -0
  122. package/types/paths.d.ts +10 -0
  123. package/types/paths.d.ts.map +1 -0
  124. package/types/presetir.d.ts +286 -0
  125. package/types/presetir.d.ts.map +1 -0
  126. package/types/prompts.d.ts +39 -0
  127. package/types/prompts.d.ts.map +1 -0
  128. package/types/schedule.d.ts +71 -0
  129. package/types/schedule.d.ts.map +1 -0
  130. package/types/serve/daemon.d.ts +133 -0
  131. package/types/serve/daemon.d.ts.map +1 -0
  132. package/types/serve/framing/grpc.d.ts +14 -0
  133. package/types/serve/framing/grpc.d.ts.map +1 -0
  134. package/types/serve/framing/http.d.ts +14 -0
  135. package/types/serve/framing/http.d.ts.map +1 -0
  136. package/types/serve/framing/ndjson.d.ts +19 -0
  137. package/types/serve/framing/ndjson.d.ts.map +1 -0
  138. package/types/serve/framing/socket.d.ts +14 -0
  139. package/types/serve/framing/socket.d.ts.map +1 -0
  140. package/types/serve/framing/stdio.d.ts +11 -0
  141. package/types/serve/framing/stdio.d.ts.map +1 -0
  142. package/types/serve/framing/token.d.ts +11 -0
  143. package/types/serve/framing/token.d.ts.map +1 -0
  144. package/types/serve/framing/ws.d.ts +13 -0
  145. package/types/serve/framing/ws.d.ts.map +1 -0
  146. package/types/serve/jsonrpc.d.ts +118 -0
  147. package/types/serve/jsonrpc.d.ts.map +1 -0
  148. package/types/serve/registry.d.ts +41 -0
  149. package/types/serve/registry.d.ts.map +1 -0
  150. package/types/session-ui.d.ts +36 -0
  151. package/types/session-ui.d.ts.map +1 -0
  152. package/types/sharekey.d.ts +35 -0
  153. package/types/sharekey.d.ts.map +1 -0
  154. package/types/tokens.d.ts +20 -0
  155. package/types/tokens.d.ts.map +1 -0
  156. package/types/transport.d.ts +138 -0
  157. package/types/transport.d.ts.map +1 -0
  158. package/types/util.d.ts +20 -0
  159. package/types/util.d.ts.map +1 -0
  160. package/vendor/biz3/README.md +37 -0
  161. package/vendor/biz3/constants/cmdCode.d.ts +48 -0
  162. package/vendor/biz3/constants/cmdCode.d.ts.map +1 -0
  163. package/vendor/biz3/constants/cmdCode.js +92 -0
  164. package/vendor/biz3/constants/messageConstants.d.ts +28 -0
  165. package/vendor/biz3/constants/messageConstants.d.ts.map +1 -0
  166. package/vendor/biz3/constants/messageConstants.js +30 -0
  167. package/vendor/biz3/constants/sesameDeviceModel.d.ts +75 -0
  168. package/vendor/biz3/constants/sesameDeviceModel.d.ts.map +1 -0
  169. package/vendor/biz3/constants/sesameDeviceModel.js +77 -0
  170. package/vendor/biz3/package.json +5 -0
@@ -0,0 +1,130 @@
1
+ // デバイス鍵共有 URL (ゲスト共有 QR) の生成 / 解析。
2
+ //
3
+ // Ported 1:1 from biz3 (CANDY-HOUSE/biz3, MIT):
4
+ // - generateInviteGuestQRCodeByInfo : references_web/src/utils/biz3utils.js:114-135
5
+ // - readQrcode (URL 解析部のみ) : references_web/src/utils/biz3utils.js:167-213
6
+ //
7
+ // biz3 web は SESAME アプリと共有するため、鍵情報を `ssm://UI?t=sk&sk=<base64>&l=<lv>&n=<name>`
8
+ // という URL にエンコードし、それを QR 画像化 (@nuintun/qrcode の dataURL) している。
9
+ // **URL 文字列の組み立て・解析は DOM 非依存**なので Node にそのまま移植できる (画像化は別 / 任意)。
10
+ // CLI は共有 URL を出力し、端末 QR 表示は任意 (cli 側で qrcode-terminal を動的 import)。
11
+ //
12
+ // sk ペイロード (hex 連結 → base64):
13
+ // deviceModel(productType, 1B) ++ secretKey(16B) ++ sesame2PublicKey ++ keyIndex(2B) ++ deviceUUID(16B)
14
+ // - SesameOS3 機種 (productType-5>=0) では sesame2PublicKey は 4B、OS2 系は 64B (readQrcode 参照)。
15
+ // - ゲスト共有 (keyLevel=2) のときは secretKey の位置に generateGuestQR で得た guestKeyId を入れる
16
+ // (biz3utils.js:121)。owner(0)/manager(1) は deviceKey.secretKey をそのまま使う。
17
+
18
+ import { Buffer } from "node:buffer";
19
+ import { productTypeFromModelName } from "./crypto.js";
20
+ import { modelNameByProductType } from "../vendor/biz3/constants/sesameDeviceModel.js";
21
+
22
+ /** SesameOS3 判定 (biz3utils.js:103-105)。productType - 5 >= 0 で OS3。 */
23
+ function isSesameOs3(productType) {
24
+ return productType - 5 >= 0;
25
+ }
26
+
27
+ /**
28
+ * デバイス鍵から共有 URL (`ssm://UI?...`) を組み立てる。biz3 generateInviteGuestQRCodeByInfo の 1:1 移植。
29
+ *
30
+ * @param {object} deviceKey デバイス鍵。devices 一覧 (listDevices) の 1 要素や getDeviceStatus 応答。
31
+ * 必須: deviceModel, sesame2PublicKey(hex), keyIndex(hex), deviceUUID。
32
+ * secretKey は guestKeyId 未指定時に必須。
33
+ * @param {object} opts
34
+ * @param {number|string} opts.keyLevel 0=owner / 1=manager / 2=guest (URL の l=)
35
+ * @param {string} [opts.guestKeyId] ゲスト共有時に secretKey 位置へ差し込む値 (generateGuestQR 応答)
36
+ * @param {string} [opts.name] 表示名 (URL の n=)。省略時 deviceKey.deviceName。
37
+ * @returns {string} `ssm://UI?t=sk&sk=<base64>&l=<lv>&n=<urlenc>`
38
+ */
39
+ export function buildShareKeyUrl(deviceKey, { keyLevel, guestKeyId, name } = {}) {
40
+ if (!deviceKey) throw new Error("deviceKey required");
41
+
42
+ const productType = productTypeFromModelName(deviceKey.deviceModel);
43
+ if (productType == null) {
44
+ throw new Error(`未知の deviceModel: ${JSON.stringify(deviceKey.deviceModel)} (productType を解決できません)`);
45
+ }
46
+ // biz3: parseInt(model,10).toString(16).padStart(2,'0')
47
+ const deviceModelHex = productType.toString(16).padStart(2, "0");
48
+
49
+ // ゲスト共有なら guestKeyId を secretKey 位置に差し込む (biz3utils.js:121)。
50
+ const secretKey = guestKeyId || deviceKey.secretKey;
51
+
52
+ // 必須 hex フィールドの検証 (欠落のまま base64 化すると壊れた鍵を共有してしまう)。
53
+ const required = {
54
+ secretKey,
55
+ sesame2PublicKey: deviceKey.sesame2PublicKey,
56
+ keyIndex: deviceKey.keyIndex,
57
+ deviceUUID: deviceKey.deviceUUID,
58
+ };
59
+ for (const [k, v] of Object.entries(required)) {
60
+ if (!v) throw new Error(`deviceKey.${k} required (共有 URL の生成に必要)`);
61
+ }
62
+
63
+ const keydata =
64
+ deviceModelHex +
65
+ secretKey +
66
+ deviceKey.sesame2PublicKey +
67
+ deviceKey.keyIndex +
68
+ String(deviceKey.deviceUUID).replace(/-/g, "");
69
+ const littleKey = Buffer.from(keydata, "hex").toString("base64");
70
+
71
+ const lvl = keyLevel ?? deviceKey.keyLevel;
72
+ const displayName = name || deviceKey.deviceName || "";
73
+ const params = [
74
+ "t=sk", // qrMode.QR_SESAMEKEY = 'sk' (biz3 constants/qrType.js)
75
+ `sk=${littleKey}`,
76
+ `l=${lvl}`,
77
+ `n=${encodeURIComponent(displayName)}`,
78
+ ].join("&");
79
+ return `ssm://UI?${params}`;
80
+ }
81
+
82
+ /**
83
+ * 共有 URL (`ssm://UI?...` 文字列) を解析して鍵情報に戻す。biz3 readQrcode の URL 解析部の移植
84
+ * (画像スキャン部 = Decoder/DOM 依存は除外。URL 文字列を直接受ける)。
85
+ *
86
+ * @param {string} url `ssm://UI?t=sk&sk=...&l=...&n=...`
87
+ * @returns {{secretKey:string, keyIndex:string, sesame2PublicKey:string, keyLevel:number|null,
88
+ * deviceModel:string|null, deviceName:string|null, deviceUUID:string}}
89
+ */
90
+ export function parseShareKeyUrl(url) {
91
+ if (!url) throw new Error("url required");
92
+ const qIdx = String(url).indexOf("?");
93
+ const params = new URLSearchParams(qIdx >= 0 ? String(url).slice(qIdx + 1) : String(url));
94
+
95
+ const skRaw = params.get("sk");
96
+ if (!skRaw) throw new Error("sk param not found in url");
97
+ // base64 中の '+' が URL 上で空白に化けるケースに対応 (biz3utils.js:173)。
98
+ const sk = skRaw.replace(/ /g, "+");
99
+ // biz3 は Buffer.from(Buffer.from(sk,'base64'),'hex') と二重化しているが、第1引数が Buffer の
100
+ // 場合 encoding は無視され単なるコピーになるため、base64 デコード結果がそのまま bytes。
101
+ const data = Buffer.from(sk, "base64");
102
+
103
+ const productType = data[0];
104
+ let secretKey, sesame2PublicKey, keyIndex, deviceUUIDHex;
105
+ if (isSesameOs3(productType)) {
106
+ secretKey = data.slice(1, 1 + 16).toString("hex");
107
+ sesame2PublicKey = data.slice(1 + 16, 1 + 16 + 4).toString("hex");
108
+ keyIndex = data.slice(1 + 16 + 4, 1 + 16 + 4 + 2).toString("hex");
109
+ deviceUUIDHex = data.slice(1 + 16 + 4 + 2).toString("hex");
110
+ } else {
111
+ secretKey = data.slice(1, 17).toString("hex");
112
+ sesame2PublicKey = data.slice(17, 81).toString("hex");
113
+ keyIndex = data.slice(81, 83).toString("hex");
114
+ deviceUUIDHex = data.slice(83, 99).toString("hex");
115
+ }
116
+ const deviceUUID = deviceUUIDHex
117
+ .replace(/(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/, "$1-$2-$3-$4-$5")
118
+ .toUpperCase();
119
+
120
+ const lStr = params.get("l");
121
+ return {
122
+ secretKey,
123
+ keyIndex,
124
+ sesame2PublicKey,
125
+ keyLevel: lStr != null && lStr !== "" ? parseInt(lStr, 10) : null,
126
+ deviceModel: modelNameByProductType[productType] ?? null,
127
+ deviceName: params.get("n"),
128
+ deviceUUID,
129
+ };
130
+ }
package/src/tokens.js ADDED
@@ -0,0 +1,53 @@
1
+ // ファイルシステム実装の TokenStore。auth.js から I/O を分離するための薄いラッパ。
2
+ // ライブラリ消費者は独自の実装 (例: keychain, in-memory) に差し替え可能。
3
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
4
+ import { dirname } from "node:path";
5
+ import { configPaths } from "./paths.js";
6
+
7
+ function readJsonOrNull(path) {
8
+ if (!existsSync(path)) return null;
9
+ return JSON.parse(readFileSync(path, "utf8"));
10
+ }
11
+
12
+ function writeJson(path, data) {
13
+ // tokens.json には idToken / refreshToken / deviceKey が入る。multi-user 環境で
14
+ // world-readable にならないよう mode 0600 / 親ディレクトリ 0700 で書き出す (Review M-5)。
15
+ //
16
+ // 注: 以下は POSIX (macOS/Linux) でのみ意味を持つ:
17
+ // - Windows では fs.writeFileSync の mode は read-only flag に degrade される
18
+ // - mkdirSync の mode は **新規作成時のみ** 適用される (既存ディレクトリの
19
+ // パーミッションは変わらない)。旧バージョンで 0755 で作られたディレクトリは
20
+ // `chmod 700 ~/.config/sesame-hub3` で手動修正が必要。
21
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
22
+ writeFileSync(path, JSON.stringify(data, null, 2) + "\n", { mode: 0o600 });
23
+ }
24
+
25
+ function unlinkIfExists(path) {
26
+ if (existsSync(path)) unlinkSync(path);
27
+ }
28
+
29
+ export class FileTokenStore {
30
+ /**
31
+ * @param {{ tokensPath: string, loginStatePath: string }} paths
32
+ */
33
+ constructor({ tokensPath, loginStatePath }) {
34
+ if (!tokensPath) throw new Error("tokensPath required");
35
+ if (!loginStatePath) throw new Error("loginStatePath required");
36
+ this.tokensPath = tokensPath;
37
+ this.loginStatePath = loginStatePath;
38
+ }
39
+
40
+ /** 既定の設定ディレクトリから組み立てる。CLI 内部はこれを使う。 */
41
+ static fromConfigDir(configDir) {
42
+ const p = configPaths(configDir);
43
+ return new FileTokenStore({ tokensPath: p.tokens, loginStatePath: p.loginState });
44
+ }
45
+
46
+ load() { return readJsonOrNull(this.tokensPath); }
47
+ save(t) { writeJson(this.tokensPath, t); }
48
+ clear() { unlinkIfExists(this.tokensPath); }
49
+
50
+ loadPending() { return readJsonOrNull(this.loginStatePath); }
51
+ savePending(s) { writeJson(this.loginStatePath, s); }
52
+ clearPending() { unlinkIfExists(this.loginStatePath); }
53
+ }