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 +5 -5
- package/dist/commands/clone.js +3 -3
- 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.js +2 -2
- package/dist/commands/rename.js +8 -8
- package/dist/commands/show.js +14 -14
- package/dist/commands/verify.js +15 -15
- package/dist/commands/write.js +17 -17
- package/dist/commands/write.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/lib/display.d.ts +1 -1
- package/dist/lib/display.js +1 -1
- package/dist/lib/prompts.d.ts +2 -2
- package/dist/lib/prompts.js +2 -2
- 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
|
@@ -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
|
|
@@ -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/
|
|
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 >
|
|
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/
|
|
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)
|
package/dist/commands/clone.js
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
149
|
+
await saveTag({
|
|
150
150
|
name,
|
|
151
151
|
type: card.type,
|
|
152
152
|
id: card.id,
|
|
@@ -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.js
CHANGED
|
@@ -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 {
|
|
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
|
|
27
|
+
await saveTag({
|
|
28
28
|
name,
|
|
29
29
|
type: card.type,
|
|
30
30
|
id: card.id,
|
package/dist/commands/rename.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
-
import {
|
|
3
|
-
import { promptText,
|
|
4
|
-
import {
|
|
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
|
|
8
|
-
if (
|
|
7
|
+
const tags = await loadTags();
|
|
8
|
+
if (tags.length === 0) {
|
|
9
9
|
printNoSavedTags();
|
|
10
10
|
return false;
|
|
11
11
|
}
|
|
12
|
-
oldName = await
|
|
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
|
|
17
|
+
const result = await renameTag(oldName, newName);
|
|
18
18
|
if (result === "not-found") {
|
|
19
|
-
|
|
19
|
+
printTagNotFound(oldName);
|
|
20
20
|
return false;
|
|
21
21
|
}
|
|
22
22
|
if (result === "name-taken") {
|
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,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,
|
|
4
|
+
import { printDetectionHint, printDoctorHint, printNoSavedTags, printTagNotFound } from "../lib/display.js";
|
|
5
5
|
import { Pm3Error, requireDevice } from "../lib/pm3.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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
|
|
12
|
-
if (
|
|
11
|
+
const tags = await loadTags();
|
|
12
|
+
if (tags.length === 0) {
|
|
13
13
|
printNoSavedTags();
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
16
|
-
name = await
|
|
16
|
+
name = await selectTag(tags, "Which saved tag to verify against?");
|
|
17
17
|
}
|
|
18
|
-
const
|
|
19
|
-
if (!
|
|
20
|
-
|
|
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 "${
|
|
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 ===
|
|
39
|
-
const typeMatch = card.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 "${
|
|
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 ${
|
|
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 ${
|
|
50
|
+
p.log.error(`Mismatch: read ${card.id}, expected ${tag.id}.`);
|
|
51
51
|
return false;
|
|
52
52
|
}
|
|
53
53
|
catch (err) {
|
package/dist/commands/write.js
CHANGED
|
@@ -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 {
|
|
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 {
|
|
9
|
-
import {
|
|
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
|
|
14
|
-
if (
|
|
13
|
+
const tags = await loadTags();
|
|
14
|
+
if (tags.length === 0) {
|
|
15
15
|
printNoSavedTags();
|
|
16
16
|
return false;
|
|
17
17
|
}
|
|
18
|
-
name = await
|
|
18
|
+
name = await selectTag(tags, "Which tag identity to write?");
|
|
19
19
|
}
|
|
20
|
-
const
|
|
21
|
-
if (!
|
|
22
|
-
|
|
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 "${
|
|
27
|
+
p.log.info(`Writing "${tag.name}" (${tag.type} ${tag.id})`);
|
|
28
28
|
// Full-card restore path
|
|
29
|
-
if (
|
|
30
|
-
return writeFullCard(
|
|
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(
|
|
32
|
+
const freq = cardFrequency(tag.type);
|
|
33
33
|
await waitForEnter(`Place a ${WriteTarget[freq]} on the antenna.`);
|
|
34
|
-
const success = await writeAndVerify({ type:
|
|
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(
|
|
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(
|
|
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 ===
|
|
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":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClG,OAAO,EAAE,gBAAgB,EAAE,
|
|
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 {
|
|
6
|
+
import { deleteTag } from "./commands/delete.js";
|
|
7
7
|
import { doctor } from "./commands/doctor.js";
|
|
8
|
-
import {
|
|
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(
|
|
109
|
-
program.command("export").description("Export all saved tag identities as JSON").action(withExitCode(
|
|
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")
|
package/dist/lib/display.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/lib/display.js
CHANGED
|
@@ -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
|
|
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) {
|
package/dist/lib/prompts.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
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
|
|
6
|
+
export declare function selectTag(tags: Tag[], message?: string): Promise<string>;
|
|
7
7
|
export declare function promptText(message: string, placeholder?: string): Promise<string>;
|
package/dist/lib/prompts.js
CHANGED
|
@@ -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
|
|
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:
|
|
41
|
+
options: tags.map((f) => ({
|
|
42
42
|
value: f.name,
|
|
43
43
|
label: f.name,
|
|
44
44
|
hint: `${f.type} ${f.id}`,
|
package/dist/lib/store.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export interface
|
|
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
|
|
10
|
-
export declare function
|
|
11
|
-
export declare function
|
|
12
|
-
export declare function
|
|
13
|
-
export declare function
|
|
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
|
|
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, "
|
|
8
|
-
|
|
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
|
|
18
|
-
const
|
|
19
|
-
const existing =
|
|
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
|
-
|
|
40
|
+
tags[existing] = tag;
|
|
22
41
|
}
|
|
23
42
|
else {
|
|
24
|
-
|
|
43
|
+
tags.push(tag);
|
|
25
44
|
}
|
|
26
45
|
await mkdir(STORE_DIR, { recursive: true });
|
|
27
|
-
await writeFile(STORE_PATH, `${JSON.stringify(
|
|
46
|
+
await writeFile(STORE_PATH, `${JSON.stringify(tags, null, 2)}\n`);
|
|
28
47
|
}
|
|
29
|
-
export async function
|
|
30
|
-
const
|
|
31
|
-
return
|
|
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
|
|
34
|
-
const
|
|
35
|
-
const index =
|
|
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 (
|
|
57
|
+
if (tags.some((f) => f.name === newName))
|
|
39
58
|
return "name-taken";
|
|
40
|
-
|
|
59
|
+
tags[index].name = newName;
|
|
41
60
|
await mkdir(STORE_DIR, { recursive: true });
|
|
42
|
-
await writeFile(STORE_PATH, `${JSON.stringify(
|
|
61
|
+
await writeFile(STORE_PATH, `${JSON.stringify(tags, null, 2)}\n`);
|
|
43
62
|
return "ok";
|
|
44
63
|
}
|
|
45
|
-
export async function
|
|
46
|
-
const
|
|
64
|
+
export async function importTags(incoming) {
|
|
65
|
+
const tags = await loadTags();
|
|
47
66
|
let added = 0;
|
|
48
67
|
let updated = 0;
|
|
49
|
-
for (const
|
|
50
|
-
const existing =
|
|
68
|
+
for (const tag of incoming) {
|
|
69
|
+
const existing = tags.findIndex((f) => f.name === tag.name);
|
|
51
70
|
if (existing >= 0) {
|
|
52
|
-
|
|
71
|
+
tags[existing] = tag;
|
|
53
72
|
updated++;
|
|
54
73
|
}
|
|
55
74
|
else {
|
|
56
|
-
|
|
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(
|
|
80
|
+
await writeFile(STORE_PATH, `${JSON.stringify(tags, null, 2)}\n`);
|
|
62
81
|
return { added, updated };
|
|
63
82
|
}
|
|
64
|
-
export async function
|
|
65
|
-
const
|
|
66
|
-
const index =
|
|
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
|
-
|
|
88
|
+
tags.splice(index, 1);
|
|
70
89
|
await mkdir(STORE_DIR, { recursive: true });
|
|
71
|
-
await writeFile(STORE_PATH, `${JSON.stringify(
|
|
90
|
+
await writeFile(STORE_PATH, `${JSON.stringify(tags, null, 2)}\n`);
|
|
72
91
|
return true;
|
|
73
92
|
}
|
|
74
93
|
//# sourceMappingURL=store.js.map
|
package/dist/lib/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/lib/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
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.
|
|
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": {
|