keyfabe 0.1.0 → 0.1.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Eugene Dobry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -8,6 +8,7 @@ A TypeScript CLI tool that wraps the Proxmark3 client to provide an ergonomic ke
8
8
  - Detects and surfaces common problems (device not found, firmware mismatch, antenna issues)
9
9
  - Stores cloned fob identities for later re-use
10
10
  - Walks you through flashing Iceman firmware on a stock Proxmark3 Easy
11
+ - Export/import fob identities for backup and sharing
11
12
 
12
13
  ## Prerequisites
13
14
 
@@ -23,9 +24,13 @@ If your device has stock firmware, `keyfabe setup` will handle building and flas
23
24
  ## Install
24
25
 
25
26
  ```sh
26
- npm install
27
- npm run build
28
- npm link # makes `keyfabe` available globally
27
+ npm install -g keyfabe
28
+ ```
29
+
30
+ Or run without installing:
31
+
32
+ ```sh
33
+ npx keyfabe
29
34
  ```
30
35
 
31
36
  ## Usage
@@ -49,8 +54,20 @@ keyfabe write <name>
49
54
  # list saved identities
50
55
  keyfabe list
51
56
 
57
+ # show details of a saved identity
58
+ keyfabe show <name>
59
+
60
+ # rename a saved identity
61
+ keyfabe rename <old-name> <new-name>
62
+
52
63
  # delete a saved identity
53
64
  keyfabe delete <name>
65
+
66
+ # export all saved identities as JSON
67
+ keyfabe export > fobs.json
68
+
69
+ # import identities from a JSON file
70
+ keyfabe import fobs.json
54
71
  ```
55
72
 
56
73
  ## Commands
@@ -79,10 +96,26 @@ Writes a previously-saved identity to a blank T55x7 fob.
79
96
 
80
97
  Lists all saved fob identities from `~/.keyfabe/fobs.json`.
81
98
 
99
+ ### `keyfabe show <name>`
100
+
101
+ Displays full details of a saved fob identity (type, ID, encoding, save date).
102
+
103
+ ### `keyfabe rename <old-name> <new-name>`
104
+
105
+ Renames a saved fob identity.
106
+
82
107
  ### `keyfabe delete <name>`
83
108
 
84
109
  Deletes a saved fob identity.
85
110
 
111
+ ### `keyfabe export`
112
+
113
+ Exports all saved fob identities as JSON to stdout. Pipe to a file for backup: `keyfabe export > fobs.json`.
114
+
115
+ ### `keyfabe import <file>`
116
+
117
+ Imports fob identities from a JSON file. New names are added, existing names are updated.
118
+
86
119
  ## Supported Card Types
87
120
 
88
121
  | Type | Read | Clone | Notes |
@@ -101,7 +134,7 @@ npm test # run tests
101
134
  npm run build # compile TypeScript
102
135
  ```
103
136
 
104
- A pre-commit hook runs lint, test, and build automatically on every commit. CI does the same on push/PR via GitHub Actions.
137
+ A pre-commit hook runs lint, test, and build automatically on every commit. CI does the same on push/PR via GitHub Actions. Publishing to npm is handled by a separate workflow triggered by GitHub releases.
105
138
 
106
139
  ## Architecture
107
140
 
@@ -115,11 +148,17 @@ src/
115
148
  clone.ts # guided clone flow
116
149
  write.ts # write saved identity
117
150
  list.ts # list saved identities
151
+ show.ts # show saved identity details
152
+ rename.ts # rename saved identity
118
153
  delete.ts # delete saved identity
154
+ export.ts # export identities as JSON
155
+ import.ts # import identities from JSON
119
156
  lib/
120
157
  pm3.ts # spawns pm3 process, sends commands
121
158
  firmware.ts # build/flash subprocess helpers
122
159
  parsers.ts # parse pm3 output (card type, ID, voltages)
123
160
  store.ts # read/write ~/.keyfabe/fobs.json
161
+ card-ops.ts # write-and-verify logic shared by clone/write
162
+ display.ts # shared display helpers and constants
124
163
  prompts.ts # interactive user prompts
125
164
  ```
@@ -3,12 +3,14 @@ import ora from "ora";
3
3
  import { writeAndVerify } from "../lib/card-ops.js";
4
4
  import { printCardInfo } from "../lib/display.js";
5
5
  import { parseLfSearch } from "../lib/parsers.js";
6
- import { Pm3Error, pm3Exec } from "../lib/pm3.js";
6
+ import { Pm3Error, pm3Exec, requireDevice } from "../lib/pm3.js";
7
7
  import { promptName, waitForEnter } from "../lib/prompts.js";
8
8
  import { saveFob } from "../lib/store.js";
9
9
  const MAX_READ_RETRIES = 3;
10
10
  const READ_RETRY_DELAY = 2000;
11
11
  export async function clone() {
12
+ if (!(await requireDevice()))
13
+ return false;
12
14
  console.log(chalk.bold("\nKeyfob Clone\n"));
13
15
  // Step 1: Read original
14
16
  await waitForEnter("Place your original keyfob on the antenna.");
@@ -1 +1 @@
1
- {"version":3,"file":"clone.js","sourceRoot":"","sources":["../../src/commands/clone.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"clone.js","sourceRoot":"","sources":["../../src/commands/clone.ts"],"names":[],"mappings":"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"}
@@ -2,10 +2,12 @@ import chalk from "chalk";
2
2
  import ora from "ora";
3
3
  import { printCardInfo } from "../lib/display.js";
4
4
  import { parseLfSearch } from "../lib/parsers.js";
5
- import { Pm3Error, pm3Exec } from "../lib/pm3.js";
5
+ import { Pm3Error, pm3Exec, requireDevice } from "../lib/pm3.js";
6
6
  import { promptName } from "../lib/prompts.js";
7
7
  import { saveFob } from "../lib/store.js";
8
8
  export async function read() {
9
+ if (!(await requireDevice()))
10
+ return false;
9
11
  let card = null;
10
12
  const spinner = ora("Searching for card (LF)...").start();
11
13
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/commands/read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,IAAI;IACtB,IAAI,IAAI,GAAqC,IAAI,CAAC;IAElD,MAAM,OAAO,GAAG,GAAG,CAAC,4BAA4B,CAAC,CAAC,KAAK,EAAE,CAAC;IAC1D,IAAI,CAAC;QACD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC1B,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;QACjF,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACjC,aAAa,CAAC,IAAI,CAAC,CAAC;IAEpB,iBAAiB;IACjB,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC;IAChC,IAAI,IAAI,EAAE,CAAC;QACP,MAAM,OAAO,CAAC;YACV,IAAI;YACJ,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/commands/read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,IAAI;IACtB,IAAI,CAAC,CAAC,MAAM,aAAa,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAE3C,IAAI,IAAI,GAAqC,IAAI,CAAC;IAElD,MAAM,OAAO,GAAG,GAAG,CAAC,4BAA4B,CAAC,CAAC,KAAK,EAAE,CAAC;IAC1D,IAAI,CAAC;QACD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC1B,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;QACjF,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACjC,aAAa,CAAC,IAAI,CAAC,CAAC;IAEpB,iBAAiB;IACjB,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC;IAChC,IAAI,IAAI,EAAE,CAAC;QACP,MAAM,OAAO,CAAC;YACV,IAAI;YACJ,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import chalk from "chalk";
2
2
  import { writeAndVerify } from "../lib/card-ops.js";
3
3
  import { printFobNotFound } from "../lib/display.js";
4
+ import { requireDevice } from "../lib/pm3.js";
4
5
  import { waitForEnter } from "../lib/prompts.js";
5
6
  import { getFob } from "../lib/store.js";
6
7
  export async function write(name) {
@@ -9,6 +10,8 @@ export async function write(name) {
9
10
  printFobNotFound(name);
10
11
  return false;
11
12
  }
13
+ if (!(await requireDevice()))
14
+ return false;
12
15
  console.log(chalk.bold(`\nWriting "${fob.name}" (${fob.type} ${fob.id})\n`));
13
16
  await waitForEnter("Place a blank T55x7 fob on the antenna.");
14
17
  const success = await writeAndVerify({ type: fob.type, id: fob.id, encoding: fob.encoding });
@@ -1 +1 @@
1
- {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/commands/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAY;IACpC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACvB,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IAE7E,MAAM,YAAY,CAAC,yCAAyC,CAAC,CAAC;IAE9D,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE7F,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC5C,OAAO,KAAK,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/commands/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAY;IACpC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACvB,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,aAAa,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAE3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IAE7E,MAAM,YAAY,CAAC,yCAAyC,CAAC,CAAC;IAE9D,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE7F,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC5C,OAAO,KAAK,CAAC;AACjB,CAAC"}
package/dist/lib/pm3.d.ts CHANGED
@@ -8,4 +8,5 @@ export interface Pm3Result {
8
8
  stderr: string;
9
9
  }
10
10
  export declare function pm3Exec(command: string, timeout?: number): Promise<Pm3Result>;
11
+ export declare function requireDevice(): Promise<boolean>;
11
12
  export declare function detectPort(): Promise<string | null>;
package/dist/lib/pm3.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { readdir } from "node:fs/promises";
3
+ import chalk from "chalk";
3
4
  const DEFAULT_TIMEOUT = 30_000;
4
5
  export class Pm3Error extends Error {
5
6
  stdout;
@@ -35,6 +36,14 @@ export async function pm3Exec(command, timeout = DEFAULT_TIMEOUT) {
35
36
  });
36
37
  });
37
38
  }
39
+ export async function requireDevice() {
40
+ const port = await detectPort();
41
+ if (!port) {
42
+ console.log(chalk.red("\nNo Proxmark3 detected. Check USB connection.\n"));
43
+ return false;
44
+ }
45
+ return true;
46
+ }
38
47
  export async function detectPort() {
39
48
  try {
40
49
  const entries = await readdir("/dev");
@@ -1 +1 @@
1
- {"version":3,"file":"pm3.js","sourceRoot":"","sources":["../../src/lib/pm3.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B,MAAM,OAAO,QAAS,SAAQ,KAAK;IAC/B,MAAM,CAAS;IACf,MAAM,CAAS;IACf,YAAY,OAAe,EAAE,MAAc,EAAE,MAAc;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;CACJ;AAOD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAe,EAAE,OAAO,GAAG,eAAe;IACpE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YAClF,MAAM,GAAG,GAAG,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACrC,IAAI,KAAK,EAAE,CAAC;gBACR,kEAAkE;gBAClE,iEAAiE;gBACjE,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACrD,MAAM,CACF,IAAI,QAAQ,CACR,yEAAyE,EACzE,GAAG,EACH,GAAG,CACN,CACJ,CAAC;oBACF,OAAO;gBACX,CAAC;gBACD,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,QAAQ,CAAC,+BAA+B,OAAO,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;oBAC3E,OAAO;gBACX,CAAC;gBACD,8CAA8C;gBAC9C,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;gBACtC,OAAO;YACX,CAAC;YACD,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC5B,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC;QAChE,OAAO,KAAK,CAAC,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"pm3.js","sourceRoot":"","sources":["../../src/lib/pm3.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B,MAAM,OAAO,QAAS,SAAQ,KAAK;IAC/B,MAAM,CAAS;IACf,MAAM,CAAS;IACf,YAAY,OAAe,EAAE,MAAc,EAAE,MAAc;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;CACJ;AAOD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAe,EAAE,OAAO,GAAG,eAAe;IACpE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YAClF,MAAM,GAAG,GAAG,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACrC,IAAI,KAAK,EAAE,CAAC;gBACR,kEAAkE;gBAClE,iEAAiE;gBACjE,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACrD,MAAM,CACF,IAAI,QAAQ,CACR,yEAAyE,EACzE,GAAG,EACH,GAAG,CACN,CACJ,CAAC;oBACF,OAAO;gBACX,CAAC;gBACD,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,QAAQ,CAAC,+BAA+B,OAAO,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;oBAC3E,OAAO;gBACX,CAAC;gBACD,8CAA8C;gBAC9C,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;gBACtC,OAAO;YACX,CAAC;YACD,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IAC/B,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC,CAAC;QAC3E,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC5B,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC;QAChE,OAAO,KAAK,CAAC,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "keyfabe",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "CLI tool for Proxmark3 keyfob cloning",
5
+ "license": "MIT",
5
6
  "type": "module",
6
7
  "bin": {
7
8
  "keyfabe": "dist/index.js"
@@ -34,7 +35,10 @@
34
35
  },
35
36
  "devDependencies": {
36
37
  "@biomejs/biome": "^2.3.14",
38
+ "@semantic-release/changelog": "^6.0.3",
39
+ "@semantic-release/git": "^10.0.1",
37
40
  "@types/node": "^25.2.2",
41
+ "semantic-release": "^25.0.3",
38
42
  "tsx": "^4.21.0",
39
43
  "typescript": "^5.9.3",
40
44
  "vitest": "^3.2.4"