keyfabe 0.9.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 CHANGED
@@ -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 > fobs.json
79
+ keyfabe export > tags.json
80
80
 
81
81
  # import identities from a JSON file
82
- keyfabe import fobs.json
82
+ keyfabe import tags.json
83
83
 
84
84
  # repair a bricked magic card (bad BCC/anticollision)
85
85
  keyfabe repair
@@ -151,7 +151,7 @@ Reads whatever tag is on the antenna and compares its ID against a saved identit
151
151
 
152
152
  ### `keyfabe list`
153
153
 
154
- Lists all saved tag identities from `~/.keyfabe/fobs.json`.
154
+ Lists all saved tag identities from `~/.keyfabe/tags.json`. Use `--json` for machine-readable output.
155
155
 
156
156
  ### `keyfabe show [name]`
157
157
 
@@ -167,7 +167,7 @@ Deletes a saved tag identity. Without a name, presents an interactive picker.
167
167
 
168
168
  ### `keyfabe export`
169
169
 
170
- Exports all saved tag identities as JSON to stdout. Pipe to a file for backup: `keyfabe export > fobs.json`.
170
+ Exports all saved tag identities as JSON to stdout. Pipe to a file for backup: `keyfabe export > tags.json`.
171
171
 
172
172
  ### `keyfabe import <file>`
173
173
 
@@ -227,7 +227,7 @@ src/
227
227
  firmware.ts # build/flash subprocess helpers
228
228
  parsers.ts # parse pm3 output (card type, ID, voltages)
229
229
  block0.ts # MIFARE Classic block 0 utilities (BCC, builder)
230
- store.ts # read/write ~/.keyfabe/fobs.json
230
+ store.ts # read/write ~/.keyfabe/tags.json
231
231
  constants.ts # shared card type and pm3 command constants
232
232
  card-ops.ts # search, write-and-verify logic shared by commands
233
233
  mf-ops.ts # MIFARE Classic full-card operations (crack, dump, restore)
@@ -6,7 +6,7 @@ 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 { saveFob } from "../lib/store.js";
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) {
@@ -65,7 +65,7 @@ export async function clone(options) {
65
65
  p.log.success("Clone successful!");
66
66
  const name = options?.saveAs ?? (await promptName());
67
67
  if (name) {
68
- await saveFob({
68
+ await saveTag({
69
69
  name,
70
70
  type: card.type,
71
71
  id: card.id,
@@ -146,7 +146,7 @@ async function cloneMifareClassic(card, options) {
146
146
  p.log.success("Full-card clone successful!");
147
147
  const name = options?.saveAs ?? (await promptName());
148
148
  if (name) {
149
- await saveFob({
149
+ await saveTag({
150
150
  name,
151
151
  type: card.type,
152
152
  id: card.id,
@@ -1 +1 @@
1
- export declare function deleteFob(name?: string): Promise<boolean>;
1
+ export declare function deleteTag(name?: string): Promise<boolean>;
@@ -1,24 +1,24 @@
1
1
  import * as p from "@clack/prompts";
2
- import { printFobNotFound, printNoSavedTags } from "../lib/display.js";
3
- import { confirm, selectFob } from "../lib/prompts.js";
4
- import { loadFobs, removeFob } from "../lib/store.js";
5
- export async function deleteFob(name) {
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 fobs = await loadFobs();
8
- if (fobs.length === 0) {
7
+ const tags = await loadTags();
8
+ if (tags.length === 0) {
9
9
  printNoSavedTags();
10
10
  return false;
11
11
  }
12
- name = await selectFob(fobs, "Which tag to delete?");
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 removeFob(name);
19
+ const removed = await removeTag(name);
20
20
  if (!removed) {
21
- printFobNotFound(name);
21
+ printTagNotFound(name);
22
22
  return false;
23
23
  }
24
24
  p.log.success(`Deleted "${name}".`);
@@ -1 +1 @@
1
- export declare function exportFobs(): Promise<boolean>;
1
+ export declare function exportTags(): Promise<boolean>;
@@ -1,13 +1,13 @@
1
- import { loadFobs } from "../lib/store.js";
2
- export async function exportFobs() {
3
- const fobs = await loadFobs();
4
- if (fobs.length === 0) {
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(fobs, null, 2)}\n`);
10
- console.error(`Exported ${fobs.length} tag(s).`);
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
@@ -1,7 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import * as p from "@clack/prompts";
3
- import { importFobs } from "../lib/store.js";
4
- function validateFobs(data) {
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 (!validateFobs(data)) {
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 importFobs(data);
35
+ const { added, updated } = await importTags(data);
36
36
  p.log.success(`Imported ${added} new, updated ${updated} existing.`);
37
37
  return true;
38
38
  }
@@ -1,21 +1,21 @@
1
1
  import * as p from "@clack/prompts";
2
- import { loadFobs } from "../lib/store.js";
2
+ import { loadTags } from "../lib/store.js";
3
3
  export async function list(options = {}) {
4
- const fobs = await loadFobs();
4
+ const tags = await loadTags();
5
5
  if (options.json) {
6
- console.log(JSON.stringify(fobs, null, 2));
6
+ console.log(JSON.stringify(tags, null, 2));
7
7
  return true;
8
8
  }
9
- if (fobs.length === 0) {
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 = fobs.some((f) => f.encoding);
13
+ const hasEncoding = tags.some((f) => f.encoding);
14
14
  const cols = {
15
- name: Math.max(12, ...fobs.map((f) => f.name.length + 2)),
16
- type: Math.max(10, ...fobs.map((f) => f.type.length + 2)),
17
- id: Math.max(16, ...fobs.map((f) => f.id.length + 2)),
18
- encoding: hasEncoding ? Math.max(12, ...fobs.map((f) => (f.encoding ?? "").length + 2)) : 0,
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 fob of fobs) {
27
- const date = fob.savedAt.slice(0, 10);
28
- let row = fob.name.padEnd(cols.name) + fob.type.padEnd(cols.type) + fob.id.padEnd(cols.id);
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 += (fob.encoding ?? "").padEnd(cols.encoding);
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 (${fobs.length})`);
35
+ p.note(`${header}\n${rows.join("\n")}`, `Saved Tags (${tags.length})`);
36
36
  return true;
37
37
  }
38
38
  //# sourceMappingURL=list.js.map
@@ -4,7 +4,7 @@ import { DetectionSummary } from "../lib/constants.js";
4
4
  import { printCardInfo, printDetectionHint, printDoctorHint } from "../lib/display.js";
5
5
  import { Pm3Error, requireDevice } from "../lib/pm3.js";
6
6
  import { promptName } from "../lib/prompts.js";
7
- import { saveFob } from "../lib/store.js";
7
+ import { saveTag } from "../lib/store.js";
8
8
  export async function read(options) {
9
9
  if (!(await requireDevice()))
10
10
  return false;
@@ -24,7 +24,7 @@ export async function read(options) {
24
24
  // Prompt to save
25
25
  const name = options?.saveAs ?? (await promptName());
26
26
  if (name) {
27
- await saveFob({
27
+ await saveTag({
28
28
  name,
29
29
  type: card.type,
30
30
  id: card.id,
@@ -1,22 +1,22 @@
1
1
  import * as p from "@clack/prompts";
2
- import { printFobNotFound, printNoSavedTags } from "../lib/display.js";
3
- import { promptText, selectFob } from "../lib/prompts.js";
4
- import { loadFobs, renameFob } from "../lib/store.js";
2
+ import { printNoSavedTags, printTagNotFound } from "../lib/display.js";
3
+ import { promptText, selectTag } from "../lib/prompts.js";
4
+ import { loadTags, renameTag } from "../lib/store.js";
5
5
  export async function rename(oldName, newName) {
6
6
  if (!oldName) {
7
- const fobs = await loadFobs();
8
- if (fobs.length === 0) {
7
+ const tags = await loadTags();
8
+ if (tags.length === 0) {
9
9
  printNoSavedTags();
10
10
  return false;
11
11
  }
12
- oldName = await selectFob(fobs, "Which tag to rename?");
12
+ oldName = await selectTag(tags, "Which tag to rename?");
13
13
  }
14
14
  if (!newName) {
15
15
  newName = await promptText("New name", "e.g. front-door");
16
16
  }
17
- const result = await renameFob(oldName, newName);
17
+ const result = await renameTag(oldName, newName);
18
18
  if (result === "not-found") {
19
- printFobNotFound(oldName);
19
+ printTagNotFound(oldName);
20
20
  return false;
21
21
  }
22
22
  if (result === "name-taken") {
@@ -1,27 +1,27 @@
1
1
  import * as p from "@clack/prompts";
2
- import { printFobNotFound, printNoSavedTags } from "../lib/display.js";
3
- import { selectFob } from "../lib/prompts.js";
4
- import { getFob, loadFobs } from "../lib/store.js";
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 fobs = await loadFobs();
8
- if (fobs.length === 0) {
7
+ const tags = await loadTags();
8
+ if (tags.length === 0) {
9
9
  printNoSavedTags();
10
10
  return false;
11
11
  }
12
- name = await selectFob(fobs, "Which tag to show?");
12
+ name = await selectTag(tags, "Which tag to show?");
13
13
  }
14
- const fob = await getFob(name);
15
- if (!fob) {
16
- printFobNotFound(name);
14
+ const tag = await getTag(name);
15
+ if (!tag) {
16
+ printTagNotFound(name);
17
17
  return false;
18
18
  }
19
19
  const lines = [
20
- `Name: ${fob.name}`,
21
- `Type: ${fob.type}`,
22
- `ID: ${fob.id}`,
23
- ...(fob.encoding ? [`Encoding: ${fob.encoding}`] : []),
24
- `Saved: ${fob.savedAt.slice(0, 10)}`,
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;
@@ -1,28 +1,28 @@
1
1
  import * as p from "@clack/prompts";
2
2
  import { searchCardWithDiagnosis } from "../lib/card-ops.js";
3
3
  import { DetectionSummary } from "../lib/constants.js";
4
- import { printDetectionHint, printDoctorHint, printFobNotFound, printNoSavedTags } from "../lib/display.js";
4
+ import { printDetectionHint, printDoctorHint, printNoSavedTags, printTagNotFound } from "../lib/display.js";
5
5
  import { Pm3Error, requireDevice } from "../lib/pm3.js";
6
- import { selectFob, waitForEnter } from "../lib/prompts.js";
7
- import { getFob, loadFobs } from "../lib/store.js";
6
+ import { selectTag, waitForEnter } from "../lib/prompts.js";
7
+ import { getTag, loadTags } from "../lib/store.js";
8
8
  export async function verify(name) {
9
9
  p.intro("Verify Tag");
10
10
  if (!name) {
11
- const fobs = await loadFobs();
12
- if (fobs.length === 0) {
11
+ const tags = await loadTags();
12
+ if (tags.length === 0) {
13
13
  printNoSavedTags();
14
14
  return false;
15
15
  }
16
- name = await selectFob(fobs, "Which saved tag to verify against?");
16
+ name = await selectTag(tags, "Which saved tag to verify against?");
17
17
  }
18
- const fob = await getFob(name);
19
- if (!fob) {
20
- printFobNotFound(name);
18
+ const tag = await getTag(name);
19
+ if (!tag) {
20
+ printTagNotFound(name);
21
21
  return false;
22
22
  }
23
23
  if (!(await requireDevice()))
24
24
  return false;
25
- p.log.info(`Verifying against "${fob.name}" (${fob.type} ${fob.id})`);
25
+ p.log.info(`Verifying against "${tag.name}" (${tag.type} ${tag.id})`);
26
26
  await waitForEnter("Place the tag to check on the antenna.");
27
27
  const spinner = p.spinner();
28
28
  spinner.start("Reading tag...");
@@ -35,19 +35,19 @@ export async function verify(name) {
35
35
  return false;
36
36
  }
37
37
  spinner.stop(`Read: ${card.type} ${card.id}`);
38
- const idMatch = card.id === fob.id;
39
- const typeMatch = card.type === fob.type;
38
+ const idMatch = card.id === tag.id;
39
+ const typeMatch = card.type === tag.type;
40
40
  if (idMatch && typeMatch) {
41
- p.log.success(`Match! ID ${card.id} matches "${fob.name}".`);
41
+ p.log.success(`Match! ID ${card.id} matches "${tag.name}".`);
42
42
  p.outro("Verification passed.");
43
43
  return true;
44
44
  }
45
45
  if (idMatch) {
46
- p.log.warn(`ID matches (${card.id}) but type differs: read ${card.type}, expected ${fob.type}.`);
46
+ p.log.warn(`ID matches (${card.id}) but type differs: read ${card.type}, expected ${tag.type}.`);
47
47
  p.outro("Partial match — ID is correct.");
48
48
  return true;
49
49
  }
50
- p.log.error(`Mismatch: read ${card.id}, expected ${fob.id}.`);
50
+ p.log.error(`Mismatch: read ${card.id}, expected ${tag.id}.`);
51
51
  return false;
52
52
  }
53
53
  catch (err) {
@@ -1,37 +1,37 @@
1
1
  import * as p from "@clack/prompts";
2
2
  import { detectMagicType, writeAndVerify } from "../lib/card-ops.js";
3
3
  import { CardType, cardFrequency, MagicCardType, Pm3Cmd, WriteTarget } from "../lib/constants.js";
4
- import { printFobNotFound, printNoSavedTags, printNotMagicHint } from "../lib/display.js";
4
+ import { printNoSavedTags, printNotMagicHint, printTagNotFound } from "../lib/display.js";
5
5
  import { restoreCard } from "../lib/mf-ops.js";
6
6
  import { parseHfSearch } from "../lib/parsers.js";
7
7
  import { pm3Exec, requireDevice } from "../lib/pm3.js";
8
- import { selectFob, waitForEnter } from "../lib/prompts.js";
9
- import { getFob, loadFobs } from "../lib/store.js";
8
+ import { selectTag, waitForEnter } from "../lib/prompts.js";
9
+ import { getTag, loadTags } from "../lib/store.js";
10
10
  export async function write(name) {
11
11
  p.intro("Write Tag");
12
12
  if (!name) {
13
- const fobs = await loadFobs();
14
- if (fobs.length === 0) {
13
+ const tags = await loadTags();
14
+ if (tags.length === 0) {
15
15
  printNoSavedTags();
16
16
  return false;
17
17
  }
18
- name = await selectFob(fobs, "Which tag identity to write?");
18
+ name = await selectTag(tags, "Which tag identity to write?");
19
19
  }
20
- const fob = await getFob(name);
21
- if (!fob) {
22
- printFobNotFound(name);
20
+ const tag = await getTag(name);
21
+ if (!tag) {
22
+ printTagNotFound(name);
23
23
  return false;
24
24
  }
25
25
  if (!(await requireDevice()))
26
26
  return false;
27
- p.log.info(`Writing "${fob.name}" (${fob.type} ${fob.id})`);
27
+ p.log.info(`Writing "${tag.name}" (${tag.type} ${tag.id})`);
28
28
  // Full-card restore path
29
- if (fob.dumpFile && (fob.type === CardType.MIFARE_CLASSIC_1K || fob.type === CardType.MIFARE_CLASSIC_4K)) {
30
- return writeFullCard(fob);
29
+ if (tag.dumpFile && (tag.type === CardType.MIFARE_CLASSIC_1K || tag.type === CardType.MIFARE_CLASSIC_4K)) {
30
+ return writeFullCard(tag);
31
31
  }
32
- const freq = cardFrequency(fob.type);
32
+ const freq = cardFrequency(tag.type);
33
33
  await waitForEnter(`Place a ${WriteTarget[freq]} on the antenna.`);
34
- const success = await writeAndVerify({ type: fob.type, id: fob.id, encoding: fob.encoding });
34
+ const success = await writeAndVerify({ type: tag.type, id: tag.id, encoding: tag.encoding });
35
35
  if (success) {
36
36
  p.outro("Write successful!");
37
37
  return true;
@@ -39,7 +39,7 @@ export async function write(name) {
39
39
  p.log.error("Write failed.");
40
40
  return false;
41
41
  }
42
- async function writeFullCard(fob) {
42
+ async function writeFullCard(tag) {
43
43
  await waitForEnter(`Place a ${WriteTarget.HF} on the antenna.`);
44
44
  // Detect magic card type
45
45
  const magicSpinner = p.spinner();
@@ -59,7 +59,7 @@ async function writeFullCard(fob) {
59
59
  // Restore all blocks
60
60
  const restoreSpinner = p.spinner();
61
61
  restoreSpinner.start("Restoring all blocks to magic card...");
62
- const restoreResult = await restoreCard(fob.dumpFile, fob.dumpFile.replace("-dump.", "-key."), fob.type);
62
+ const restoreResult = await restoreCard(tag.dumpFile, tag.dumpFile.replace("-dump.", "-key."), tag.type);
63
63
  if (!restoreResult.success) {
64
64
  restoreSpinner.stop("Restore failed.");
65
65
  p.log.error(`${restoreResult.failedBlocks} block(s) failed to write.`);
@@ -72,7 +72,7 @@ async function writeFullCard(fob) {
72
72
  verifySpinner.start("Verifying clone...");
73
73
  const { stdout: verifyOut } = await pm3Exec(Pm3Cmd.HF_SEARCH);
74
74
  const readback = parseHfSearch(verifyOut);
75
- if (readback && readback.id === fob.id) {
75
+ if (readback && readback.id === tag.id) {
76
76
  verifySpinner.stop("Verification passed — UIDs match");
77
77
  }
78
78
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/commands/write.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/commands/write.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3,9 +3,9 @@ import { createRequire } from "node:module";
3
3
  import * as p from "@clack/prompts";
4
4
  import { program } from "commander";
5
5
  import { clone } from "./commands/clone.js";
6
- import { deleteFob } from "./commands/delete.js";
6
+ import { deleteTag } from "./commands/delete.js";
7
7
  import { doctor } from "./commands/doctor.js";
8
- import { exportFobs } from "./commands/export.js";
8
+ import { exportTags } from "./commands/export.js";
9
9
  import { importFile } from "./commands/import.js";
10
10
  import { list } from "./commands/list.js";
11
11
  import { read } from "./commands/read.js";
@@ -105,8 +105,8 @@ program
105
105
  .command("delete")
106
106
  .description("Delete a saved tag identity")
107
107
  .argument("[name]", "name of the saved tag identity")
108
- .action(withExitCode(deleteFob));
109
- program.command("export").description("Export all saved tag identities as JSON").action(withExitCode(exportFobs));
108
+ .action(withExitCode(deleteTag));
109
+ program.command("export").description("Export all saved tag identities as JSON").action(withExitCode(exportTags));
110
110
  program
111
111
  .command("import")
112
112
  .description("Import tag identities from a JSON file")
@@ -7,7 +7,7 @@ export declare function printBrewInstall(): void;
7
7
  export declare function printCardInfo(card: CardInfo): void;
8
8
  export declare function printDoctorHint(): void;
9
9
  export declare function printNoSavedTags(): void;
10
- export declare function printFobNotFound(name: string): void;
10
+ export declare function printTagNotFound(name: string): void;
11
11
  export declare function printDetectionHint(diagnosis: DetectionKindName): void;
12
12
  export declare function printNotMagicHint(): void;
13
13
  export declare function printFrequencyMismatchHint(expected: "LF"): void;
@@ -19,7 +19,7 @@ export function printDoctorHint() {
19
19
  export function printNoSavedTags() {
20
20
  p.log.warn("No saved tags. Use `keyfabe read` or `keyfabe clone` first.");
21
21
  }
22
- export function printFobNotFound(name) {
22
+ export function printTagNotFound(name) {
23
23
  p.log.error(`No saved tag named "${name}". Use \`keyfabe list\` to see saved tags.`);
24
24
  }
25
25
  export function printDetectionHint(diagnosis) {
@@ -1,7 +1,7 @@
1
- import type { Fob } from "./store.js";
1
+ import type { Tag } from "./store.js";
2
2
  export declare function isInteractive(): boolean;
3
3
  export declare function confirm(message: string): Promise<boolean>;
4
4
  export declare function waitForEnter(message: string): Promise<void>;
5
5
  export declare function promptName(): Promise<string | null>;
6
- export declare function selectFob(fobs: Fob[], message?: string): Promise<string>;
6
+ export declare function selectTag(tags: Tag[], message?: string): Promise<string>;
7
7
  export declare function promptText(message: string, placeholder?: string): Promise<string>;
@@ -31,14 +31,14 @@ export async function promptName() {
31
31
  const trimmed = value.trim();
32
32
  return trimmed || null;
33
33
  }
34
- export async function selectFob(fobs, message = "Select a tag") {
34
+ export async function selectTag(tags, message = "Select a tag") {
35
35
  if (!isInteractive()) {
36
36
  p.log.error("Tag name must be provided as a CLI argument in non-interactive mode.");
37
37
  process.exit(1);
38
38
  }
39
39
  const value = await p.select({
40
40
  message,
41
- options: fobs.map((f) => ({
41
+ options: tags.map((f) => ({
42
42
  value: f.name,
43
43
  label: f.name,
44
44
  hint: `${f.type} ${f.id}`,
@@ -1,4 +1,4 @@
1
- export interface Fob {
1
+ export interface Tag {
2
2
  name: string;
3
3
  type: string;
4
4
  id: string;
@@ -6,12 +6,12 @@ export interface Fob {
6
6
  dumpFile?: string;
7
7
  savedAt: string;
8
8
  }
9
- export declare function loadFobs(): Promise<Fob[]>;
10
- export declare function saveFob(fob: Fob): Promise<void>;
11
- export declare function getFob(name: string): Promise<Fob | undefined>;
12
- export declare function renameFob(oldName: string, newName: string): Promise<"ok" | "not-found" | "name-taken">;
13
- export declare function importFobs(incoming: Fob[]): Promise<{
9
+ export declare function loadTags(): Promise<Tag[]>;
10
+ export declare function saveTag(tag: Tag): Promise<void>;
11
+ export declare function getTag(name: string): Promise<Tag | undefined>;
12
+ export declare function renameTag(oldName: string, newName: string): Promise<"ok" | "not-found" | "name-taken">;
13
+ export declare function importTags(incoming: Tag[]): Promise<{
14
14
  added: number;
15
15
  updated: number;
16
16
  }>;
17
- export declare function removeFob(name: string): Promise<boolean>;
17
+ export declare function removeTag(name: string): Promise<boolean>;
package/dist/lib/store.js CHANGED
@@ -1,11 +1,30 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
1
+ import { access, rename as fsRename, mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
4
  const STORE_DIR = process.env.KEYFABE_STORE_PATH
5
5
  ? dirname(process.env.KEYFABE_STORE_PATH)
6
6
  : join(homedir(), ".keyfabe");
7
- const STORE_PATH = process.env.KEYFABE_STORE_PATH ?? join(STORE_DIR, "fobs.json");
8
- export async function loadFobs() {
7
+ const STORE_PATH = process.env.KEYFABE_STORE_PATH ?? join(STORE_DIR, "tags.json");
8
+ const OLD_STORE_PATH = join(STORE_DIR, "fobs.json");
9
+ async function migrateStore() {
10
+ try {
11
+ await access(OLD_STORE_PATH);
12
+ // Old file exists — check if new file already exists
13
+ try {
14
+ await access(STORE_PATH);
15
+ // Both exist — don't overwrite, user can resolve manually
16
+ }
17
+ catch {
18
+ // Only old exists — rename it
19
+ await fsRename(OLD_STORE_PATH, STORE_PATH);
20
+ }
21
+ }
22
+ catch {
23
+ // Old file doesn't exist — nothing to migrate
24
+ }
25
+ }
26
+ export async function loadTags() {
27
+ await migrateStore();
9
28
  try {
10
29
  const data = await readFile(STORE_PATH, "utf-8");
11
30
  return JSON.parse(data);
@@ -14,61 +33,61 @@ export async function loadFobs() {
14
33
  return [];
15
34
  }
16
35
  }
17
- export async function saveFob(fob) {
18
- const fobs = await loadFobs();
19
- const existing = fobs.findIndex((f) => f.name === fob.name);
36
+ export async function saveTag(tag) {
37
+ const tags = await loadTags();
38
+ const existing = tags.findIndex((f) => f.name === tag.name);
20
39
  if (existing >= 0) {
21
- fobs[existing] = fob;
40
+ tags[existing] = tag;
22
41
  }
23
42
  else {
24
- fobs.push(fob);
43
+ tags.push(tag);
25
44
  }
26
45
  await mkdir(STORE_DIR, { recursive: true });
27
- await writeFile(STORE_PATH, `${JSON.stringify(fobs, null, 2)}\n`);
46
+ await writeFile(STORE_PATH, `${JSON.stringify(tags, null, 2)}\n`);
28
47
  }
29
- export async function getFob(name) {
30
- const fobs = await loadFobs();
31
- return fobs.find((f) => f.name === name);
48
+ export async function getTag(name) {
49
+ const tags = await loadTags();
50
+ return tags.find((f) => f.name === name);
32
51
  }
33
- export async function renameFob(oldName, newName) {
34
- const fobs = await loadFobs();
35
- const index = fobs.findIndex((f) => f.name === oldName);
52
+ export async function renameTag(oldName, newName) {
53
+ const tags = await loadTags();
54
+ const index = tags.findIndex((f) => f.name === oldName);
36
55
  if (index < 0)
37
56
  return "not-found";
38
- if (fobs.some((f) => f.name === newName))
57
+ if (tags.some((f) => f.name === newName))
39
58
  return "name-taken";
40
- fobs[index].name = newName;
59
+ tags[index].name = newName;
41
60
  await mkdir(STORE_DIR, { recursive: true });
42
- await writeFile(STORE_PATH, `${JSON.stringify(fobs, null, 2)}\n`);
61
+ await writeFile(STORE_PATH, `${JSON.stringify(tags, null, 2)}\n`);
43
62
  return "ok";
44
63
  }
45
- export async function importFobs(incoming) {
46
- const fobs = await loadFobs();
64
+ export async function importTags(incoming) {
65
+ const tags = await loadTags();
47
66
  let added = 0;
48
67
  let updated = 0;
49
- for (const fob of incoming) {
50
- const existing = fobs.findIndex((f) => f.name === fob.name);
68
+ for (const tag of incoming) {
69
+ const existing = tags.findIndex((f) => f.name === tag.name);
51
70
  if (existing >= 0) {
52
- fobs[existing] = fob;
71
+ tags[existing] = tag;
53
72
  updated++;
54
73
  }
55
74
  else {
56
- fobs.push(fob);
75
+ tags.push(tag);
57
76
  added++;
58
77
  }
59
78
  }
60
79
  await mkdir(STORE_DIR, { recursive: true });
61
- await writeFile(STORE_PATH, `${JSON.stringify(fobs, null, 2)}\n`);
80
+ await writeFile(STORE_PATH, `${JSON.stringify(tags, null, 2)}\n`);
62
81
  return { added, updated };
63
82
  }
64
- export async function removeFob(name) {
65
- const fobs = await loadFobs();
66
- const index = fobs.findIndex((f) => f.name === name);
83
+ export async function removeTag(name) {
84
+ const tags = await loadTags();
85
+ const index = tags.findIndex((f) => f.name === name);
67
86
  if (index < 0)
68
87
  return false;
69
- fobs.splice(index, 1);
88
+ tags.splice(index, 1);
70
89
  await mkdir(STORE_DIR, { recursive: true });
71
- await writeFile(STORE_PATH, `${JSON.stringify(fobs, null, 2)}\n`);
90
+ await writeFile(STORE_PATH, `${JSON.stringify(tags, null, 2)}\n`);
72
91
  return true;
73
92
  }
74
93
  //# sourceMappingURL=store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/lib/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/lib/store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keyfabe",
3
- "version": "0.9.0",
3
+ "version": "1.0.0",
4
4
  "description": "CLI tool for Proxmark3 RFID tag cloning",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,6 +24,7 @@
24
24
  "nfc",
25
25
  "mifare",
26
26
  "keyfob",
27
+ "tag",
27
28
  "clone"
28
29
  ],
29
30
  "scripts": {