keyfabe 0.8.0 → 1.0.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.
- package/README.md +43 -10
- package/dist/commands/clone.js +12 -10
- package/dist/commands/clone.js.map +1 -1
- package/dist/commands/delete.d.ts +1 -1
- package/dist/commands/delete.js +9 -9
- package/dist/commands/export.d.ts +1 -1
- package/dist/commands/export.js +6 -6
- package/dist/commands/import.js +4 -4
- package/dist/commands/list.js +14 -14
- package/dist/commands/read.d.ts +3 -1
- package/dist/commands/read.js +11 -9
- package/dist/commands/read.js.map +1 -1
- package/dist/commands/rename.js +9 -17
- package/dist/commands/rename.js.map +1 -1
- package/dist/commands/show.js +14 -14
- package/dist/commands/verify.js +21 -19
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/write.js +17 -17
- package/dist/commands/write.js.map +1 -1
- package/dist/index.js +11 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/card-ops.d.ts +6 -0
- package/dist/lib/card-ops.js +43 -3
- package/dist/lib/card-ops.js.map +1 -1
- package/dist/lib/constants.d.ts +16 -0
- package/dist/lib/constants.js +15 -0
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/display.d.ts +3 -1
- package/dist/lib/display.js +5 -2
- package/dist/lib/display.js.map +1 -1
- package/dist/lib/parsers.d.ts +2 -0
- package/dist/lib/parsers.js +4 -0
- package/dist/lib/parsers.js.map +1 -1
- package/dist/lib/prompts.d.ts +4 -2
- package/dist/lib/prompts.js +26 -2
- package/dist/lib/prompts.js.map +1 -1
- package/dist/lib/store.d.ts +7 -7
- package/dist/lib/store.js +49 -30
- package/dist/lib/store.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -52,10 +52,10 @@ keyfabe doctor
|
|
|
52
52
|
keyfabe setup
|
|
53
53
|
|
|
54
54
|
# guided interactive clone flow (read original → write to blank)
|
|
55
|
-
keyfabe clone
|
|
55
|
+
keyfabe clone [--save-as <name>]
|
|
56
56
|
|
|
57
57
|
# read and identify a tag without cloning
|
|
58
|
-
keyfabe read
|
|
58
|
+
keyfabe read [--save-as <name>]
|
|
59
59
|
|
|
60
60
|
# write a previously-saved identity to a blank tag
|
|
61
61
|
keyfabe write [name]
|
|
@@ -76,10 +76,10 @@ keyfabe rename [old-name] [new-name]
|
|
|
76
76
|
keyfabe delete [name]
|
|
77
77
|
|
|
78
78
|
# export all saved identities as JSON
|
|
79
|
-
keyfabe export >
|
|
79
|
+
keyfabe export > tags.json
|
|
80
80
|
|
|
81
81
|
# import identities from a JSON file
|
|
82
|
-
keyfabe import
|
|
82
|
+
keyfabe import tags.json
|
|
83
83
|
|
|
84
84
|
# repair a bricked magic card (bad BCC/anticollision)
|
|
85
85
|
keyfabe repair
|
|
@@ -87,6 +87,39 @@ keyfabe repair
|
|
|
87
87
|
|
|
88
88
|
Commands that take `[name]` arguments are fully optional — when omitted, you'll get an interactive tag picker.
|
|
89
89
|
|
|
90
|
+
### Scripting / Non-Interactive Mode
|
|
91
|
+
|
|
92
|
+
keyfabe auto-detects non-interactive mode when stdin is not a TTY (e.g., piped input, cron jobs, called from another process). No flags needed — interactive prompts are automatically skipped or replaced with sensible defaults:
|
|
93
|
+
|
|
94
|
+
- **Pause prompts** (`waitForEnter`) — logged and skipped (scripted callers handle card placement themselves)
|
|
95
|
+
- **Save prompts** (`promptName`) — skipped (use `--save-as` to save)
|
|
96
|
+
- **Confirmation prompts** — auto-yes (you explicitly invoked the command)
|
|
97
|
+
- **Selection prompts** — exit with error (provide the name as a CLI argument instead)
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
# read a tag and save it non-interactively
|
|
101
|
+
keyfabe read --save-as front-door < /dev/null
|
|
102
|
+
|
|
103
|
+
# clone and save in one shot
|
|
104
|
+
keyfabe clone --save-as lobby-key < /dev/null
|
|
105
|
+
|
|
106
|
+
# write a saved identity (already non-interactive with name arg)
|
|
107
|
+
keyfabe write front-door < /dev/null
|
|
108
|
+
|
|
109
|
+
# verify a tag against a saved identity
|
|
110
|
+
keyfabe verify front-door < /dev/null
|
|
111
|
+
|
|
112
|
+
# export/import work without changes
|
|
113
|
+
keyfabe export > backup.json
|
|
114
|
+
keyfabe import backup.json
|
|
115
|
+
|
|
116
|
+
# list and show work without changes
|
|
117
|
+
keyfabe list --json
|
|
118
|
+
keyfabe show front-door
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Commands that require interactive selection (e.g., `keyfabe delete` without a name argument) will exit with a clear error message when run non-interactively.
|
|
122
|
+
|
|
90
123
|
## Commands
|
|
91
124
|
|
|
92
125
|
### `keyfabe doctor`
|
|
@@ -99,14 +132,14 @@ Interactive wizard for flashing Iceman firmware to a stock Proxmark3 Easy. Handl
|
|
|
99
132
|
|
|
100
133
|
### `keyfabe clone`
|
|
101
134
|
|
|
102
|
-
Guided clone flow: reads the original tag (LF and HF), writes to a blank card, and verifies the readback. Optionally saves the identity for later use.
|
|
135
|
+
Guided clone flow: reads the original tag (LF and HF), writes to a blank card, and verifies the readback. Optionally saves the identity for later use. Use `--save-as <name>` to save without prompting.
|
|
103
136
|
|
|
104
137
|
- **LF cards** (EM410x, HID Prox): writes the UID to a blank T55x7
|
|
105
138
|
- **MIFARE Classic**: full-card clone — automatically cracks all sector keys, dumps all blocks, and restores them onto a magic card. Supports standard chips via `autopwn` and FM11RF08S chips via automatic fallback recovery (~28 min)
|
|
106
139
|
|
|
107
140
|
### `keyfabe read`
|
|
108
141
|
|
|
109
|
-
Reads and identifies whatever tag is on the antenna. Searches LF first, then falls back to HF. Supports EM410x, HID Prox, MIFARE Classic, MIFARE Ultralight, MIFARE DESFire, and ISO 14443-A. Optionally saves the identity.
|
|
142
|
+
Reads and identifies whatever tag is on the antenna. Searches LF first, then falls back to HF. Supports EM410x, HID Prox, MIFARE Classic, MIFARE Ultralight, MIFARE DESFire, and ISO 14443-A. Optionally saves the identity. Use `--save-as <name>` to save without prompting.
|
|
110
143
|
|
|
111
144
|
### `keyfabe write [name]`
|
|
112
145
|
|
|
@@ -118,7 +151,7 @@ Reads whatever tag is on the antenna and compares its ID against a saved identit
|
|
|
118
151
|
|
|
119
152
|
### `keyfabe list`
|
|
120
153
|
|
|
121
|
-
Lists all saved tag identities from `~/.keyfabe/
|
|
154
|
+
Lists all saved tag identities from `~/.keyfabe/tags.json`. Use `--json` for machine-readable output.
|
|
122
155
|
|
|
123
156
|
### `keyfabe show [name]`
|
|
124
157
|
|
|
@@ -134,7 +167,7 @@ Deletes a saved tag identity. Without a name, presents an interactive picker.
|
|
|
134
167
|
|
|
135
168
|
### `keyfabe export`
|
|
136
169
|
|
|
137
|
-
Exports all saved tag identities as JSON to stdout. Pipe to a file for backup: `keyfabe export >
|
|
170
|
+
Exports all saved tag identities as JSON to stdout. Pipe to a file for backup: `keyfabe export > tags.json`.
|
|
138
171
|
|
|
139
172
|
### `keyfabe import <file>`
|
|
140
173
|
|
|
@@ -194,10 +227,10 @@ src/
|
|
|
194
227
|
firmware.ts # build/flash subprocess helpers
|
|
195
228
|
parsers.ts # parse pm3 output (card type, ID, voltages)
|
|
196
229
|
block0.ts # MIFARE Classic block 0 utilities (BCC, builder)
|
|
197
|
-
store.ts # read/write ~/.keyfabe/
|
|
230
|
+
store.ts # read/write ~/.keyfabe/tags.json
|
|
198
231
|
constants.ts # shared card type and pm3 command constants
|
|
199
232
|
card-ops.ts # search, write-and-verify logic shared by commands
|
|
200
233
|
mf-ops.ts # MIFARE Classic full-card operations (crack, dump, restore)
|
|
201
234
|
display.ts # shared display helpers and constants
|
|
202
|
-
prompts.ts # interactive user prompts
|
|
235
|
+
prompts.ts # interactive user prompts (auto-detects non-interactive mode)
|
|
203
236
|
```
|
package/dist/commands/clone.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
-
import { detectMagicType,
|
|
3
|
-
import { CardType, cardFrequency, MagicCardType, Pm3Cmd, WriteTarget } from "../lib/constants.js";
|
|
4
|
-
import { printCardInfo, printDoctorHint, printFullCardCloneProgress, printNotMagicHint } from "../lib/display.js";
|
|
2
|
+
import { detectMagicType, searchCardWithDiagnosis, writeAndVerify } from "../lib/card-ops.js";
|
|
3
|
+
import { CardType, cardFrequency, DetectionSummary, MagicCardType, Pm3Cmd, WriteTarget } from "../lib/constants.js";
|
|
4
|
+
import { printCardInfo, printDetectionHint, printDoctorHint, printFullCardCloneProgress, printNotMagicHint, } from "../lib/display.js";
|
|
5
5
|
import { crackKeys, dumpCard, restoreCard } from "../lib/mf-ops.js";
|
|
6
6
|
import { parseHfSearch } from "../lib/parsers.js";
|
|
7
7
|
import { Pm3Error, pm3Exec, requireDevice } from "../lib/pm3.js";
|
|
8
8
|
import { promptName, waitForEnter } from "../lib/prompts.js";
|
|
9
|
-
import {
|
|
9
|
+
import { saveTag } from "../lib/store.js";
|
|
10
10
|
const MAX_READ_RETRIES = 3;
|
|
11
11
|
const READ_RETRY_DELAY = 2000;
|
|
12
12
|
export async function clone(options) {
|
|
@@ -20,13 +20,15 @@ export async function clone(options) {
|
|
|
20
20
|
const s = p.spinner();
|
|
21
21
|
s.start(`Reading original (attempt ${attempt}/${MAX_READ_RETRIES})...`);
|
|
22
22
|
try {
|
|
23
|
-
|
|
24
|
-
if (card) {
|
|
23
|
+
const result = await searchCardWithDiagnosis();
|
|
24
|
+
if (result.card) {
|
|
25
|
+
card = result.card;
|
|
25
26
|
s.stop("Original tag read");
|
|
26
27
|
break;
|
|
27
28
|
}
|
|
28
|
-
s.stop(
|
|
29
|
-
p.log.error(
|
|
29
|
+
s.stop(DetectionSummary[result.diagnosis]);
|
|
30
|
+
p.log.error(DetectionSummary[result.diagnosis]);
|
|
31
|
+
printDetectionHint(result.diagnosis);
|
|
30
32
|
}
|
|
31
33
|
catch (err) {
|
|
32
34
|
if (err instanceof Pm3Error) {
|
|
@@ -63,7 +65,7 @@ export async function clone(options) {
|
|
|
63
65
|
p.log.success("Clone successful!");
|
|
64
66
|
const name = options?.saveAs ?? (await promptName());
|
|
65
67
|
if (name) {
|
|
66
|
-
await
|
|
68
|
+
await saveTag({
|
|
67
69
|
name,
|
|
68
70
|
type: card.type,
|
|
69
71
|
id: card.id,
|
|
@@ -144,7 +146,7 @@ async function cloneMifareClassic(card, options) {
|
|
|
144
146
|
p.log.success("Full-card clone successful!");
|
|
145
147
|
const name = options?.saveAs ?? (await promptName());
|
|
146
148
|
if (name) {
|
|
147
|
-
await
|
|
149
|
+
await saveTag({
|
|
148
150
|
name,
|
|
149
151
|
type: card.type,
|
|
150
152
|
id: card.id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clone.js","sourceRoot":"","sources":["../../src/commands/clone.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"clone.js","sourceRoot":"","sources":["../../src/commands/clone.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function deleteTag(name?: string): Promise<boolean>;
|
package/dist/commands/delete.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
-
import {
|
|
3
|
-
import { confirm,
|
|
4
|
-
import {
|
|
5
|
-
export async function
|
|
2
|
+
import { printNoSavedTags, printTagNotFound } from "../lib/display.js";
|
|
3
|
+
import { confirm, selectTag } from "../lib/prompts.js";
|
|
4
|
+
import { loadTags, removeTag } from "../lib/store.js";
|
|
5
|
+
export async function deleteTag(name) {
|
|
6
6
|
if (!name) {
|
|
7
|
-
const
|
|
8
|
-
if (
|
|
7
|
+
const tags = await loadTags();
|
|
8
|
+
if (tags.length === 0) {
|
|
9
9
|
printNoSavedTags();
|
|
10
10
|
return false;
|
|
11
11
|
}
|
|
12
|
-
name = await
|
|
12
|
+
name = await selectTag(tags, "Which tag to delete?");
|
|
13
13
|
}
|
|
14
14
|
const shouldDelete = await confirm(`Delete "${name}"?`);
|
|
15
15
|
if (!shouldDelete) {
|
|
16
16
|
p.cancel("Deletion cancelled.");
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
|
-
const removed = await
|
|
19
|
+
const removed = await removeTag(name);
|
|
20
20
|
if (!removed) {
|
|
21
|
-
|
|
21
|
+
printTagNotFound(name);
|
|
22
22
|
return false;
|
|
23
23
|
}
|
|
24
24
|
p.log.success(`Deleted "${name}".`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function exportTags(): Promise<boolean>;
|
package/dist/commands/export.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export async function
|
|
3
|
-
const
|
|
4
|
-
if (
|
|
1
|
+
import { loadTags } from "../lib/store.js";
|
|
2
|
+
export async function exportTags() {
|
|
3
|
+
const tags = await loadTags();
|
|
4
|
+
if (tags.length === 0) {
|
|
5
5
|
console.error("No saved tags to export.");
|
|
6
6
|
return false;
|
|
7
7
|
}
|
|
8
8
|
// Output clean JSON to stdout for piping
|
|
9
|
-
process.stdout.write(`${JSON.stringify(
|
|
10
|
-
console.error(`Exported ${
|
|
9
|
+
process.stdout.write(`${JSON.stringify(tags, null, 2)}\n`);
|
|
10
|
+
console.error(`Exported ${tags.length} tag(s).`);
|
|
11
11
|
return true;
|
|
12
12
|
}
|
|
13
13
|
//# sourceMappingURL=export.js.map
|
package/dist/commands/import.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import * as p from "@clack/prompts";
|
|
3
|
-
import {
|
|
4
|
-
function
|
|
3
|
+
import { importTags } from "../lib/store.js";
|
|
4
|
+
function validateTags(data) {
|
|
5
5
|
if (!Array.isArray(data))
|
|
6
6
|
return false;
|
|
7
7
|
return data.every((item) => typeof item === "object" &&
|
|
@@ -28,11 +28,11 @@ export async function importFile(filePath) {
|
|
|
28
28
|
p.log.error("Invalid JSON.");
|
|
29
29
|
return false;
|
|
30
30
|
}
|
|
31
|
-
if (!
|
|
31
|
+
if (!validateTags(data)) {
|
|
32
32
|
p.log.error("Invalid format. Expected an array of tag objects with name, type, id, and savedAt.");
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
35
|
-
const { added, updated } = await
|
|
35
|
+
const { added, updated } = await importTags(data);
|
|
36
36
|
p.log.success(`Imported ${added} new, updated ${updated} existing.`);
|
|
37
37
|
return true;
|
|
38
38
|
}
|
package/dist/commands/list.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
-
import {
|
|
2
|
+
import { loadTags } from "../lib/store.js";
|
|
3
3
|
export async function list(options = {}) {
|
|
4
|
-
const
|
|
4
|
+
const tags = await loadTags();
|
|
5
5
|
if (options.json) {
|
|
6
|
-
console.log(JSON.stringify(
|
|
6
|
+
console.log(JSON.stringify(tags, null, 2));
|
|
7
7
|
return true;
|
|
8
8
|
}
|
|
9
|
-
if (
|
|
9
|
+
if (tags.length === 0) {
|
|
10
10
|
p.log.info("No saved tags. Use `keyfabe read` or `keyfabe clone` to save one.");
|
|
11
11
|
return true;
|
|
12
12
|
}
|
|
13
|
-
const hasEncoding =
|
|
13
|
+
const hasEncoding = tags.some((f) => f.encoding);
|
|
14
14
|
const cols = {
|
|
15
|
-
name: Math.max(12, ...
|
|
16
|
-
type: Math.max(10, ...
|
|
17
|
-
id: Math.max(16, ...
|
|
18
|
-
encoding: hasEncoding ? Math.max(12, ...
|
|
15
|
+
name: Math.max(12, ...tags.map((f) => f.name.length + 2)),
|
|
16
|
+
type: Math.max(10, ...tags.map((f) => f.type.length + 2)),
|
|
17
|
+
id: Math.max(16, ...tags.map((f) => f.id.length + 2)),
|
|
18
|
+
encoding: hasEncoding ? Math.max(12, ...tags.map((f) => (f.encoding ?? "").length + 2)) : 0,
|
|
19
19
|
};
|
|
20
20
|
let header = "Name".padEnd(cols.name) + "Type".padEnd(cols.type) + "ID".padEnd(cols.id);
|
|
21
21
|
if (hasEncoding) {
|
|
@@ -23,16 +23,16 @@ export async function list(options = {}) {
|
|
|
23
23
|
}
|
|
24
24
|
header += "Saved";
|
|
25
25
|
const rows = [];
|
|
26
|
-
for (const
|
|
27
|
-
const date =
|
|
28
|
-
let row =
|
|
26
|
+
for (const tag of tags) {
|
|
27
|
+
const date = tag.savedAt.slice(0, 10);
|
|
28
|
+
let row = tag.name.padEnd(cols.name) + tag.type.padEnd(cols.type) + tag.id.padEnd(cols.id);
|
|
29
29
|
if (hasEncoding) {
|
|
30
|
-
row += (
|
|
30
|
+
row += (tag.encoding ?? "").padEnd(cols.encoding);
|
|
31
31
|
}
|
|
32
32
|
row += date;
|
|
33
33
|
rows.push(row);
|
|
34
34
|
}
|
|
35
|
-
p.note(`${header}\n${rows.join("\n")}`, `Saved Tags (${
|
|
35
|
+
p.note(`${header}\n${rows.join("\n")}`, `Saved Tags (${tags.length})`);
|
|
36
36
|
return true;
|
|
37
37
|
}
|
|
38
38
|
//# sourceMappingURL=list.js.map
|
package/dist/commands/read.d.ts
CHANGED
package/dist/commands/read.js
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { searchCardWithDiagnosis } from "../lib/card-ops.js";
|
|
3
|
+
import { DetectionSummary } from "../lib/constants.js";
|
|
4
|
+
import { printCardInfo, printDetectionHint, printDoctorHint } from "../lib/display.js";
|
|
4
5
|
import { Pm3Error, requireDevice } from "../lib/pm3.js";
|
|
5
6
|
import { promptName } from "../lib/prompts.js";
|
|
6
|
-
import {
|
|
7
|
-
export async function read() {
|
|
7
|
+
import { saveTag } from "../lib/store.js";
|
|
8
|
+
export async function read(options) {
|
|
8
9
|
if (!(await requireDevice()))
|
|
9
10
|
return false;
|
|
10
11
|
p.intro("Read Tag");
|
|
11
12
|
const s = p.spinner();
|
|
12
13
|
s.start("Searching for tag...");
|
|
13
14
|
try {
|
|
14
|
-
const card = await
|
|
15
|
+
const { card, diagnosis } = await searchCardWithDiagnosis();
|
|
15
16
|
if (!card) {
|
|
16
|
-
s.stop(
|
|
17
|
-
p.log.error(
|
|
17
|
+
s.stop(DetectionSummary[diagnosis]);
|
|
18
|
+
p.log.error(DetectionSummary[diagnosis]);
|
|
19
|
+
printDetectionHint(diagnosis);
|
|
18
20
|
return false;
|
|
19
21
|
}
|
|
20
22
|
s.stop("Tag detected");
|
|
21
23
|
printCardInfo(card);
|
|
22
24
|
// Prompt to save
|
|
23
|
-
const name = await promptName();
|
|
25
|
+
const name = options?.saveAs ?? (await promptName());
|
|
24
26
|
if (name) {
|
|
25
|
-
await
|
|
27
|
+
await saveTag({
|
|
26
28
|
name,
|
|
27
29
|
type: card.type,
|
|
28
30
|
id: card.id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/commands/read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/commands/read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAA6B;IACpD,IAAI,CAAC,CAAC,MAAM,aAAa,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAE3C,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAEpB,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChC,IAAI,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,uBAAuB,EAAE,CAAC;QAC5D,IAAI,CAAC,IAAI,EAAE,CAAC;YACR,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;YACpC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;YACzC,kBAAkB,CAAC,SAAS,CAAC,CAAC;YAC9B,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACvB,aAAa,CAAC,IAAI,CAAC,CAAC;QAEpB,iBAAiB;QACjB,MAAM,IAAI,GAAG,OAAO,EAAE,MAAM,IAAI,CAAC,MAAM,UAAU,EAAE,CAAC,CAAC;QACrD,IAAI,IAAI,EAAE,CAAC;YACP,MAAM,OAAO,CAAC;gBACV,IAAI;gBACJ,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;YACH,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;YAC1B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACpB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACzB,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBACpC,eAAe,EAAE,CAAC;YACtB,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACzB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC"}
|
package/dist/commands/rename.js
CHANGED
|
@@ -1,30 +1,22 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
function handleCancel(value) {
|
|
6
|
-
if (p.isCancel(value)) {
|
|
7
|
-
p.cancel("Operation cancelled.");
|
|
8
|
-
process.exit(0);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
2
|
+
import { printNoSavedTags, printTagNotFound } from "../lib/display.js";
|
|
3
|
+
import { promptText, selectTag } from "../lib/prompts.js";
|
|
4
|
+
import { loadTags, renameTag } from "../lib/store.js";
|
|
11
5
|
export async function rename(oldName, newName) {
|
|
12
6
|
if (!oldName) {
|
|
13
|
-
const
|
|
14
|
-
if (
|
|
7
|
+
const tags = await loadTags();
|
|
8
|
+
if (tags.length === 0) {
|
|
15
9
|
printNoSavedTags();
|
|
16
10
|
return false;
|
|
17
11
|
}
|
|
18
|
-
oldName = await
|
|
12
|
+
oldName = await selectTag(tags, "Which tag to rename?");
|
|
19
13
|
}
|
|
20
14
|
if (!newName) {
|
|
21
|
-
|
|
22
|
-
handleCancel(value);
|
|
23
|
-
newName = value;
|
|
15
|
+
newName = await promptText("New name", "e.g. front-door");
|
|
24
16
|
}
|
|
25
|
-
const result = await
|
|
17
|
+
const result = await renameTag(oldName, newName);
|
|
26
18
|
if (result === "not-found") {
|
|
27
|
-
|
|
19
|
+
printTagNotFound(oldName);
|
|
28
20
|
return false;
|
|
29
21
|
}
|
|
30
22
|
if (result === "name-taken") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rename.js","sourceRoot":"","sources":["../../src/commands/rename.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"rename.js","sourceRoot":"","sources":["../../src/commands/rename.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAAgB,EAAE,OAAgB;IAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpB,gBAAgB,EAAE,CAAC;YACnB,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,GAAG,MAAM,UAAU,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,OAAiB,CAAC,CAAC;IAE3D,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QACzB,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC1B,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;QAC1B,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,OAAO,+DAA+D,CAAC,CAAC;QACpG,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,OAAO,SAAS,OAAO,IAAI,CAAC,CAAC;IACvD,OAAO,IAAI,CAAC;AAChB,CAAC"}
|
package/dist/commands/show.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { printNoSavedTags, printTagNotFound } from "../lib/display.js";
|
|
3
|
+
import { selectTag } from "../lib/prompts.js";
|
|
4
|
+
import { getTag, loadTags } from "../lib/store.js";
|
|
5
5
|
export async function show(name) {
|
|
6
6
|
if (!name) {
|
|
7
|
-
const
|
|
8
|
-
if (
|
|
7
|
+
const tags = await loadTags();
|
|
8
|
+
if (tags.length === 0) {
|
|
9
9
|
printNoSavedTags();
|
|
10
10
|
return false;
|
|
11
11
|
}
|
|
12
|
-
name = await
|
|
12
|
+
name = await selectTag(tags, "Which tag to show?");
|
|
13
13
|
}
|
|
14
|
-
const
|
|
15
|
-
if (!
|
|
16
|
-
|
|
14
|
+
const tag = await getTag(name);
|
|
15
|
+
if (!tag) {
|
|
16
|
+
printTagNotFound(name);
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
19
|
const lines = [
|
|
20
|
-
`Name: ${
|
|
21
|
-
`Type: ${
|
|
22
|
-
`ID: ${
|
|
23
|
-
...(
|
|
24
|
-
`Saved: ${
|
|
20
|
+
`Name: ${tag.name}`,
|
|
21
|
+
`Type: ${tag.type}`,
|
|
22
|
+
`ID: ${tag.id}`,
|
|
23
|
+
...(tag.encoding ? [`Encoding: ${tag.encoding}`] : []),
|
|
24
|
+
`Saved: ${tag.savedAt.slice(0, 10)}`,
|
|
25
25
|
];
|
|
26
26
|
p.note(lines.join("\n"), "Tag Details");
|
|
27
27
|
return true;
|
package/dist/commands/verify.js
CHANGED
|
@@ -1,51 +1,53 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { searchCardWithDiagnosis } from "../lib/card-ops.js";
|
|
3
|
+
import { DetectionSummary } from "../lib/constants.js";
|
|
4
|
+
import { printDetectionHint, printDoctorHint, printNoSavedTags, printTagNotFound } from "../lib/display.js";
|
|
4
5
|
import { Pm3Error, requireDevice } from "../lib/pm3.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
6
|
+
import { selectTag, waitForEnter } from "../lib/prompts.js";
|
|
7
|
+
import { getTag, loadTags } from "../lib/store.js";
|
|
7
8
|
export async function verify(name) {
|
|
8
9
|
p.intro("Verify Tag");
|
|
9
10
|
if (!name) {
|
|
10
|
-
const
|
|
11
|
-
if (
|
|
11
|
+
const tags = await loadTags();
|
|
12
|
+
if (tags.length === 0) {
|
|
12
13
|
printNoSavedTags();
|
|
13
14
|
return false;
|
|
14
15
|
}
|
|
15
|
-
name = await
|
|
16
|
+
name = await selectTag(tags, "Which saved tag to verify against?");
|
|
16
17
|
}
|
|
17
|
-
const
|
|
18
|
-
if (!
|
|
19
|
-
|
|
18
|
+
const tag = await getTag(name);
|
|
19
|
+
if (!tag) {
|
|
20
|
+
printTagNotFound(name);
|
|
20
21
|
return false;
|
|
21
22
|
}
|
|
22
23
|
if (!(await requireDevice()))
|
|
23
24
|
return false;
|
|
24
|
-
p.log.info(`Verifying against "${
|
|
25
|
+
p.log.info(`Verifying against "${tag.name}" (${tag.type} ${tag.id})`);
|
|
25
26
|
await waitForEnter("Place the tag to check on the antenna.");
|
|
26
27
|
const spinner = p.spinner();
|
|
27
28
|
spinner.start("Reading tag...");
|
|
28
29
|
try {
|
|
29
|
-
const card = await
|
|
30
|
+
const { card, diagnosis } = await searchCardWithDiagnosis();
|
|
30
31
|
if (!card) {
|
|
31
|
-
spinner.stop(
|
|
32
|
-
p.log.error(
|
|
32
|
+
spinner.stop(DetectionSummary[diagnosis]);
|
|
33
|
+
p.log.error(DetectionSummary[diagnosis]);
|
|
34
|
+
printDetectionHint(diagnosis);
|
|
33
35
|
return false;
|
|
34
36
|
}
|
|
35
37
|
spinner.stop(`Read: ${card.type} ${card.id}`);
|
|
36
|
-
const idMatch = card.id ===
|
|
37
|
-
const typeMatch = card.type ===
|
|
38
|
+
const idMatch = card.id === tag.id;
|
|
39
|
+
const typeMatch = card.type === tag.type;
|
|
38
40
|
if (idMatch && typeMatch) {
|
|
39
|
-
p.log.success(`Match! ID ${card.id} matches "${
|
|
41
|
+
p.log.success(`Match! ID ${card.id} matches "${tag.name}".`);
|
|
40
42
|
p.outro("Verification passed.");
|
|
41
43
|
return true;
|
|
42
44
|
}
|
|
43
45
|
if (idMatch) {
|
|
44
|
-
p.log.warn(`ID matches (${card.id}) but type differs: read ${card.type}, expected ${
|
|
46
|
+
p.log.warn(`ID matches (${card.id}) but type differs: read ${card.type}, expected ${tag.type}.`);
|
|
45
47
|
p.outro("Partial match — ID is correct.");
|
|
46
48
|
return true;
|
|
47
49
|
}
|
|
48
|
-
p.log.error(`Mismatch: read ${card.id}, expected ${
|
|
50
|
+
p.log.error(`Mismatch: read ${card.id}, expected ${tag.id}.`);
|
|
49
51
|
return false;
|
|
50
52
|
}
|
|
51
53
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"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"}
|