@mks2508/binary-cookies-parser 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/LICENSE +21 -0
- package/README.md +261 -0
- package/dist/cjs/index.js +1 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +33 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 MKS2508
|
|
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
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# binary-cookies-parser 🍪
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@mks2508/binary-cookies-parser)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](https://bun.sh)
|
|
7
|
+
|
|
8
|
+
A modern, TypeScript-native parser for macOS binary cookies files (`.binarycookies`). Parse Safari and macOS app cookies with full type safety and zero dependencies.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Zero Dependencies** - Pure TypeScript implementation
|
|
13
|
+
- **Dual Package** - ESM and CommonJS support
|
|
14
|
+
- **Fast** - Built with Bun, works with Node.js
|
|
15
|
+
- **macOS Native** - Handles Safari and native app cookies
|
|
16
|
+
- **Simple API** - One function to parse cookies
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# npm
|
|
22
|
+
npm install binary-cookies-parser
|
|
23
|
+
|
|
24
|
+
# bun
|
|
25
|
+
bun add binary-cookies-parser
|
|
26
|
+
|
|
27
|
+
# yarn
|
|
28
|
+
yarn add binary-cookies-parser
|
|
29
|
+
|
|
30
|
+
# pnpm
|
|
31
|
+
pnpm add binary-cookies-parser
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### Basic Parsing
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { parseBinaryCookies } from 'binary-cookies-parser';
|
|
40
|
+
import { homedir } from 'node:os';
|
|
41
|
+
import { join } from 'node:path';
|
|
42
|
+
|
|
43
|
+
// Parse Safari cookies
|
|
44
|
+
const safariCookies = await parseBinaryCookies(
|
|
45
|
+
join(homedir(), 'Library/Cookies/Cookies.binarycookies')
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// Each cookie has:
|
|
49
|
+
// - name: string
|
|
50
|
+
// - value: string
|
|
51
|
+
// - url: string (domain)
|
|
52
|
+
// - path: string
|
|
53
|
+
// - flags: number (0=none, 1=secure, 4=httpOnly, 5=both)
|
|
54
|
+
// - expiration: Date
|
|
55
|
+
// - creation: Date
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Filtering Cookies
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Filter by domain
|
|
62
|
+
const googleCookies = cookies.filter(c => c.url.includes('google.com'));
|
|
63
|
+
|
|
64
|
+
// Filter by secure flag
|
|
65
|
+
const secureCookies = cookies.filter(c => c.flags & 1);
|
|
66
|
+
|
|
67
|
+
// Filter by expiration
|
|
68
|
+
const validCookies = cookies.filter(c => c.expiration > new Date());
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Converting to Playwright Format
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
const playwrightCookies = cookies.map(c => ({
|
|
75
|
+
name: c.name,
|
|
76
|
+
value: c.value,
|
|
77
|
+
domain: c.url,
|
|
78
|
+
path: c.path,
|
|
79
|
+
expires: Math.floor(c.expiration.getTime() / 1000),
|
|
80
|
+
httpOnly: !!(c.flags & 4),
|
|
81
|
+
secure: !!(c.flags & 1),
|
|
82
|
+
sameSite: 'Lax' as const
|
|
83
|
+
}));
|
|
84
|
+
|
|
85
|
+
// Use with Playwright
|
|
86
|
+
await context.addCookies(playwrightCookies);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Using the Class API
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { BinaryCookiesParser } from 'binary-cookies-parser';
|
|
93
|
+
|
|
94
|
+
const parser = new BinaryCookiesParser();
|
|
95
|
+
const cookies = await parser.parse('/path/to/Cookies.binarycookies');
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## API Reference
|
|
99
|
+
|
|
100
|
+
### `parseBinaryCookies(cookiePath: string): Promise<BinaryCookie[]>`
|
|
101
|
+
|
|
102
|
+
Parses a binary cookies file and returns an array of cookies.
|
|
103
|
+
|
|
104
|
+
**Parameters:**
|
|
105
|
+
- `cookiePath` - Absolute path to the `.binarycookies` file
|
|
106
|
+
|
|
107
|
+
**Returns:**
|
|
108
|
+
- `Promise<BinaryCookie[]>` - Array of parsed cookies
|
|
109
|
+
|
|
110
|
+
**Throws:**
|
|
111
|
+
- `Error` if file doesn't exist
|
|
112
|
+
- `Error` if file format is invalid
|
|
113
|
+
|
|
114
|
+
### `BinaryCookie` Interface
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
interface BinaryCookie {
|
|
118
|
+
name: string; // Cookie name
|
|
119
|
+
value: string; // Cookie value
|
|
120
|
+
url: string; // Domain (e.g., ".apple.com")
|
|
121
|
+
path: string; // Path (e.g., "/")
|
|
122
|
+
flags: number; // Flags (0=none, 1=secure, 4=httpOnly, 5=both)
|
|
123
|
+
expiration: Date; // Expiration date
|
|
124
|
+
creation: Date; // Creation date
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Cookie Flags
|
|
129
|
+
|
|
130
|
+
| Flag | Meaning |
|
|
131
|
+
|------|---------|
|
|
132
|
+
| 0 | No flags |
|
|
133
|
+
| 1 | Secure cookie |
|
|
134
|
+
| 4 | HttpOnly cookie |
|
|
135
|
+
| 5 | Secure + HttpOnly |
|
|
136
|
+
|
|
137
|
+
## Common Use Cases
|
|
138
|
+
|
|
139
|
+
### Extract Safari Cookies for Automation
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { parseBinaryCookies } from 'binary-cookies-parser';
|
|
143
|
+
import { homedir } from 'node:os';
|
|
144
|
+
import { join } from 'node:path';
|
|
145
|
+
|
|
146
|
+
const cookies = await parseBinaryCookies(
|
|
147
|
+
join(homedir(), 'Library/Cookies/Cookies.binarycookies')
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// Use with Puppeteer, Playwright, etc.
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Parse macOS App Cookies
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { parseBinaryCookies } from 'binary-cookies-parser';
|
|
157
|
+
import { homedir } from 'node:os';
|
|
158
|
+
import { join } from 'node:path';
|
|
159
|
+
|
|
160
|
+
// Example: Amazon Prime Video app
|
|
161
|
+
const primeCookies = await parseBinaryCookies(
|
|
162
|
+
join(
|
|
163
|
+
homedir(),
|
|
164
|
+
'Library/Containers/com.amazon.aiv.AIVApp/Data/Library/Cookies/Cookies.binarycookies'
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Cookie Migration
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// Export cookies from Safari
|
|
173
|
+
const cookies = await parseBinaryCookies('/path/to/safari/cookies');
|
|
174
|
+
|
|
175
|
+
// Convert to JSON for backup
|
|
176
|
+
await Bun.write('cookies-backup.json', JSON.stringify(cookies, null, 2));
|
|
177
|
+
|
|
178
|
+
// Filter and import to another browser
|
|
179
|
+
const importCookies = cookies.filter(c =>
|
|
180
|
+
c.url.includes('important-domain.com')
|
|
181
|
+
);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Platform Support
|
|
185
|
+
|
|
186
|
+
- **macOS** - ✅ Full support (Safari, native apps)
|
|
187
|
+
- **Linux** - ❌ Not applicable (no .binarycookies files)
|
|
188
|
+
- **Windows** - ❌ Not applicable (no .binarycookies files)
|
|
189
|
+
|
|
190
|
+
This library is specifically for parsing macOS binary cookies files. For cross-platform cookie management, consider using browser automation tools.
|
|
191
|
+
|
|
192
|
+
## Examples
|
|
193
|
+
|
|
194
|
+
See the [`examples/`](./examples) directory for complete working examples:
|
|
195
|
+
|
|
196
|
+
- [`basic-usage.ts`](./examples/basic-usage.ts) - Parse Safari cookies and convert to Playwright format
|
|
197
|
+
|
|
198
|
+
Run examples:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
bun run examples/basic-usage.ts
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Development
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# Install dependencies
|
|
208
|
+
bun install
|
|
209
|
+
|
|
210
|
+
# Run tests
|
|
211
|
+
bun test
|
|
212
|
+
|
|
213
|
+
# Build for npm
|
|
214
|
+
bun run build
|
|
215
|
+
|
|
216
|
+
# Generate types
|
|
217
|
+
bun run types
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Technical Details
|
|
221
|
+
|
|
222
|
+
### Binary Format
|
|
223
|
+
|
|
224
|
+
The `.binarycookies` format is a proprietary Apple format used by Safari and macOS applications. This parser implements the complete specification:
|
|
225
|
+
|
|
226
|
+
- File header validation (`cook` magic bytes)
|
|
227
|
+
- Multi-page cookie storage
|
|
228
|
+
- Mac epoch time conversion (978307200 offset)
|
|
229
|
+
- Cookie flag parsing
|
|
230
|
+
- Null-terminated string extraction
|
|
231
|
+
|
|
232
|
+
### Performance
|
|
233
|
+
|
|
234
|
+
- Zero external dependencies
|
|
235
|
+
- Single-pass parsing
|
|
236
|
+
- Efficient buffer operations
|
|
237
|
+
- Minimal memory allocations
|
|
238
|
+
|
|
239
|
+
## Credits
|
|
240
|
+
|
|
241
|
+
Inspired by the original [node-binary-cookies](https://github.com/jlipps/node-binary-cookies) by Jonathan Lipps, but completely rewritten in modern TypeScript with:
|
|
242
|
+
|
|
243
|
+
- Full type safety
|
|
244
|
+
- Async/await API
|
|
245
|
+
- Zero dependencies
|
|
246
|
+
- Dual ESM/CJS support
|
|
247
|
+
- Bun optimization
|
|
248
|
+
|
|
249
|
+
## License
|
|
250
|
+
|
|
251
|
+
MIT © 2025 MKS2508
|
|
252
|
+
|
|
253
|
+
## Contributing
|
|
254
|
+
|
|
255
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
256
|
+
|
|
257
|
+
## Links
|
|
258
|
+
|
|
259
|
+
- [npm package](https://www.npmjs.com/package/@mks2508/binary-cookies-parser)
|
|
260
|
+
- [GitHub repository](https://github.com/mks2508/binary-cookies-parser)
|
|
261
|
+
- [Issue tracker](https://github.com/mks2508/binary-cookies-parser/issues)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var D=Object.create;var{getPrototypeOf:O,defineProperty:M,getOwnPropertyNames:Z,getOwnPropertyDescriptor:S}=Object,_=Object.prototype.hasOwnProperty;var B=(E,q,F)=>{F=E!=null?D(O(E)):{};let G=q||!E||!E.__esModule?M(F,"default",{value:E,enumerable:!0}):F;for(let L of Z(E))if(!_.call(G,L))M(G,L,{get:()=>E[L],enumerable:!0});return G},Y=new WeakMap,m=(E)=>{var q=Y.get(E),F;if(q)return q;if(q=M({},"__esModule",{value:!0}),E&&typeof E==="object"||typeof E==="function")Z(E).map((G)=>!_.call(q,G)&&M(q,G,{get:()=>E[G],enumerable:!(F=S(E,G))||F.enumerable}));return Y.set(E,q),q};var C=(E,q)=>{for(var F in q)M(E,F,{get:q[F],enumerable:!0,configurable:!0,set:(G)=>q[F]=()=>G})};var x={};C(x,{parseBinaryCookies:()=>I,BinaryCookiesParser:()=>U});module.exports=m(x);var $=B(require("node:fs/promises")),w=require("node:fs");class U{cookiePath=null;currentBufferPosition=0;data=null;numPages=0;bufferSize=0;pages=[];pageSizes=[];cookies=[];async parse(E){if(this.reset(),this.cookiePath=E,!w.existsSync(E))throw Error(`Cookie file not found: ${E}`);await this.openFile(),this.getNumPages(),this.getPageSizes(),this.getPages();for(let q=0;q<this.pages.length;q++){this.getNumCookies(q),this.getCookieOffsets(q),this.getCookieData(q);for(let F=0;F<this.pages[q].cookies.length;F++){let G=this.parseCookieData(q,F);this.cookies.push(G)}}return this.cookies}reset(){this.cookiePath=null,this.currentBufferPosition=0,this.data=null,this.numPages=0,this.bufferSize=0,this.pages=[],this.pageSizes=[],this.cookies=[]}async openFile(){if(!this.cookiePath)throw Error("Cookie path not set");let E=await $.default.readFile(this.cookiePath);if(this.data=E,this.bufferSize=E.length,this.readSlice(4).toString()!=="cook")throw Error('Invalid binary cookies file format (missing "cook" header)')}readSlice(E){if(!this.data)throw Error("No data loaded");let q=this.data.subarray(this.currentBufferPosition,this.currentBufferPosition+E);return this.currentBufferPosition+=E,q}readIntBE(){if(!this.data)throw Error("No data loaded");let E=this.data.readInt32BE(this.currentBufferPosition);return this.currentBufferPosition+=4,E}readIntLE(){if(!this.data)throw Error("No data loaded");let E=this.data.readInt32LE(this.currentBufferPosition);return this.currentBufferPosition+=4,E}getNumPages(){return this.numPages=this.readIntBE(),this.numPages}getPageSizes(){for(let E=0;E<this.numPages;E++)this.pageSizes.push(this.readIntBE());return this.pageSizes}getPages(){for(let E of this.pageSizes)this.pages.push({buffer:this.readSlice(E),bufferPosition:0,numCookies:0,cookieOffsets:[],cookies:[]});return this.pages}getNumCookies(E){let q=this.pages[E];q.bufferPosition=0;let F=q.buffer.readInt32BE(q.bufferPosition);if(q.bufferPosition+=4,F!==256)throw Error(`Invalid page header: expected 256, got ${F}`);return q.numCookies=q.buffer.readInt32LE(q.bufferPosition),q.bufferPosition+=4,q.numCookies}getCookieOffsets(E){let q=this.pages[E];q.cookieOffsets=[];for(let F=0;F<q.numCookies;F++)q.cookieOffsets.push(q.buffer.readInt32LE(q.bufferPosition)),q.bufferPosition+=4;return q.cookieOffsets}getCookieData(E){let q=this.pages[E];q.cookies=[];for(let F of q.cookieOffsets){let G=q.buffer.readInt32LE(F);try{q.cookies.push({buffer:q.buffer.subarray(F,F+G)})}catch{q.cookies.push({buffer:q.buffer.subarray(F)})}}return q.cookies}parseCookieData(E,q){let L=this.pages[E].cookies[q].buffer,y=978307200,J=0,l=L.readInt32LE(J);J+=4;let K=L.readInt32LE(J);J+=8;let d=L.readUInt32LE(J),V={},z=["url","name","path","value"];for(let N of z)J+=4,V[N]=L.readInt32LE(J);J+=4;let h=L.readUInt32LE(J);J+=8;let A=L.readDoubleLE(J)+978307200,H=new Date(A*1000);J+=8;let T=L.readDoubleLE(J)+978307200,j=new Date(T*1000),W={flags:K,expiration:H,creation:j};for(let[N,v]of Object.entries(V)){let X="",Q=v,R="";do R=L.toString("utf8",Q,Q+1),X+=R,Q++;while(R!=="\x00");W[N]=X.replace(/\u0000/g,"").trim()}return W}}async function I(E){return new U().parse(E)}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { BinaryCookie } from './types';
|
|
2
|
+
export type { BinaryCookie, CookiePage } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Parser for macOS binary cookies files (.binarycookies)
|
|
5
|
+
*
|
|
6
|
+
* These files are used by Safari and other macOS applications to store cookies
|
|
7
|
+
* in a binary format that's more efficient than plain text.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { BinaryCookiesParser } from 'binary-cookies-parser';
|
|
12
|
+
*
|
|
13
|
+
* const parser = new BinaryCookiesParser();
|
|
14
|
+
* const cookies = await parser.parse('/path/to/Cookies.binarycookies');
|
|
15
|
+
* console.log(cookies);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare class BinaryCookiesParser {
|
|
19
|
+
private cookiePath;
|
|
20
|
+
private currentBufferPosition;
|
|
21
|
+
private data;
|
|
22
|
+
private numPages;
|
|
23
|
+
private bufferSize;
|
|
24
|
+
private pages;
|
|
25
|
+
private pageSizes;
|
|
26
|
+
private cookies;
|
|
27
|
+
/**
|
|
28
|
+
* Parse a binary cookies file and return an array of cookies
|
|
29
|
+
*
|
|
30
|
+
* @param cookiePath - Absolute path to the .binarycookies file
|
|
31
|
+
* @returns Array of parsed cookies
|
|
32
|
+
* @throws {Error} If file doesn't exist or has invalid format
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const parser = new BinaryCookiesParser();
|
|
37
|
+
* const cookies = await parser.parse('/Users/user/Library/Cookies/Cookies.binarycookies');
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
parse(cookiePath: string): Promise<BinaryCookie[]>;
|
|
41
|
+
private reset;
|
|
42
|
+
private openFile;
|
|
43
|
+
private readSlice;
|
|
44
|
+
private readIntBE;
|
|
45
|
+
private readIntLE;
|
|
46
|
+
private getNumPages;
|
|
47
|
+
private getPageSizes;
|
|
48
|
+
private getPages;
|
|
49
|
+
private getNumCookies;
|
|
50
|
+
private getCookieOffsets;
|
|
51
|
+
private getCookieData;
|
|
52
|
+
private parseCookieData;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Convenience function to parse a binary cookies file
|
|
56
|
+
*
|
|
57
|
+
* @param cookiePath - Absolute path to the .binarycookies file
|
|
58
|
+
* @returns Array of parsed cookies
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import { parseBinaryCookies } from 'binary-cookies-parser';
|
|
63
|
+
*
|
|
64
|
+
* const cookies = await parseBinaryCookies('/path/to/Cookies.binarycookies');
|
|
65
|
+
* console.log(cookies);
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function parseBinaryCookies(cookiePath: string): Promise<BinaryCookie[]>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import z from"node:fs/promises";import{existsSync as A}from"node:fs";class W{cookiePath=null;currentBufferPosition=0;data=null;numPages=0;bufferSize=0;pages=[];pageSizes=[];cookies=[];async parse(E){if(this.reset(),this.cookiePath=E,!A(E))throw Error(`Cookie file not found: ${E}`);await this.openFile(),this.getNumPages(),this.getPageSizes(),this.getPages();for(let q=0;q<this.pages.length;q++){this.getNumCookies(q),this.getCookieOffsets(q),this.getCookieData(q);for(let F=0;F<this.pages[q].cookies.length;F++){let L=this.parseCookieData(q,F);this.cookies.push(L)}}return this.cookies}reset(){this.cookiePath=null,this.currentBufferPosition=0,this.data=null,this.numPages=0,this.bufferSize=0,this.pages=[],this.pageSizes=[],this.cookies=[]}async openFile(){if(!this.cookiePath)throw Error("Cookie path not set");let E=await z.readFile(this.cookiePath);if(this.data=E,this.bufferSize=E.length,this.readSlice(4).toString()!=="cook")throw Error('Invalid binary cookies file format (missing "cook" header)')}readSlice(E){if(!this.data)throw Error("No data loaded");let q=this.data.subarray(this.currentBufferPosition,this.currentBufferPosition+E);return this.currentBufferPosition+=E,q}readIntBE(){if(!this.data)throw Error("No data loaded");let E=this.data.readInt32BE(this.currentBufferPosition);return this.currentBufferPosition+=4,E}readIntLE(){if(!this.data)throw Error("No data loaded");let E=this.data.readInt32LE(this.currentBufferPosition);return this.currentBufferPosition+=4,E}getNumPages(){return this.numPages=this.readIntBE(),this.numPages}getPageSizes(){for(let E=0;E<this.numPages;E++)this.pageSizes.push(this.readIntBE());return this.pageSizes}getPages(){for(let E of this.pageSizes)this.pages.push({buffer:this.readSlice(E),bufferPosition:0,numCookies:0,cookieOffsets:[],cookies:[]});return this.pages}getNumCookies(E){let q=this.pages[E];q.bufferPosition=0;let F=q.buffer.readInt32BE(q.bufferPosition);if(q.bufferPosition+=4,F!==256)throw Error(`Invalid page header: expected 256, got ${F}`);return q.numCookies=q.buffer.readInt32LE(q.bufferPosition),q.bufferPosition+=4,q.numCookies}getCookieOffsets(E){let q=this.pages[E];q.cookieOffsets=[];for(let F=0;F<q.numCookies;F++)q.cookieOffsets.push(q.buffer.readInt32LE(q.bufferPosition)),q.bufferPosition+=4;return q.cookieOffsets}getCookieData(E){let q=this.pages[E];q.cookies=[];for(let F of q.cookieOffsets){let L=q.buffer.readInt32LE(F);try{q.cookies.push({buffer:q.buffer.subarray(F,F+L)})}catch{q.cookies.push({buffer:q.buffer.subarray(F)})}}return q.cookies}parseCookieData(E,q){let J=this.pages[E].cookies[q].buffer,H=978307200,G=0,T=J.readInt32LE(G);G+=4;let X=J.readInt32LE(G);G+=8;let j=J.readUInt32LE(G),R={},Y=["url","name","path","value"];for(let M of Y)G+=4,R[M]=J.readInt32LE(G);G+=4;let v=J.readUInt32LE(G);G+=8;let Z=J.readDoubleLE(G)+978307200,_=new Date(Z*1000);G+=8;let $=J.readDoubleLE(G)+978307200,w=new Date($*1000),U={flags:X,expiration:_,creation:w};for(let[M,K]of Object.entries(R)){let V="",N=K,Q="";do Q=J.toString("utf8",N,N+1),V+=Q,N++;while(Q!=="\x00");U[M]=V.replace(/\u0000/g,"").trim()}return U}}async function S(E){return new W().parse(E)}export{S as parseBinaryCookies,W as BinaryCookiesParser};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a parsed binary cookie from macOS .binarycookies file
|
|
3
|
+
*/
|
|
4
|
+
export interface BinaryCookie {
|
|
5
|
+
/** Cookie name */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Cookie value */
|
|
8
|
+
value: string;
|
|
9
|
+
/** Domain the cookie belongs to (e.g., ".apple.com") */
|
|
10
|
+
url: string;
|
|
11
|
+
/** Cookie path (e.g., "/") */
|
|
12
|
+
path: string;
|
|
13
|
+
/** Cookie flags (0=none, 1=secure, 4=httpOnly, 5=both) */
|
|
14
|
+
flags: number;
|
|
15
|
+
/** Cookie expiration date */
|
|
16
|
+
expiration: Date;
|
|
17
|
+
/** Cookie creation date */
|
|
18
|
+
creation: Date;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Internal representation of a cookie page
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export interface CookiePage {
|
|
25
|
+
buffer: Buffer;
|
|
26
|
+
bufferPosition: number;
|
|
27
|
+
numCookies: number;
|
|
28
|
+
cookieOffsets: number[];
|
|
29
|
+
cookies: Array<{
|
|
30
|
+
buffer: Buffer;
|
|
31
|
+
data?: BinaryCookie;
|
|
32
|
+
}>;
|
|
33
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mks2508/binary-cookies-parser",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Modern TypeScript parser for macOS binary cookies files (.binarycookies). Parse Safari and app cookies with zero dependencies.",
|
|
5
|
+
"author": "MKS2508",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/cjs/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/cjs/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"keywords": [
|
|
24
|
+
"cookies",
|
|
25
|
+
"binarycookies",
|
|
26
|
+
"safari",
|
|
27
|
+
"macos",
|
|
28
|
+
"parser",
|
|
29
|
+
"typescript",
|
|
30
|
+
"playwright",
|
|
31
|
+
"puppeteer",
|
|
32
|
+
"automation",
|
|
33
|
+
"binary",
|
|
34
|
+
"cookie-parser",
|
|
35
|
+
"apple"
|
|
36
|
+
],
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/mks2508/binary-cookies-parser.git"
|
|
40
|
+
},
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/mks2508/binary-cookies-parser/issues"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/mks2508/binary-cookies-parser#readme",
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18.0.0"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "rm -rf dist && bun build ./src/index.ts --outdir ./dist --format esm --target node --minify --external '*' && bun build ./src/index.ts --outdir ./dist/cjs --format cjs --target node --minify --external '*'",
|
|
50
|
+
"types": "tsc --project tsconfig.build.json",
|
|
51
|
+
"prepublishOnly": "bun run build && bun run types",
|
|
52
|
+
"test": "bun test",
|
|
53
|
+
"example": "bun run examples/basic-usage.ts"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/bun": "latest",
|
|
57
|
+
"typescript": "^5.0.0"
|
|
58
|
+
}
|
|
59
|
+
}
|