-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfile_token_storage.ts
More file actions
144 lines (122 loc) · 4.11 KB
/
file_token_storage.ts
File metadata and controls
144 lines (122 loc) · 4.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// file_token_storage.ts
import * as path from "@std/path";
import { ensureDir } from "@std/fs";
export class FileTokenStorage {
private tokenDir: string;
constructor() {
const homeDir = Deno.env.get("HOME") || Deno.env.get("USERPROFILE") || ".";
this.tokenDir = path.join(homeDir, ".deno_tokens");
}
private getTokenPath(key: string): string {
// Sanitize key for safe filename
const safeKey = key.replace(/[^a-zA-Z0-9_-]/g, "_");
return path.join(this.tokenDir, `${safeKey}.token`);
}
async store(key: string, token: string): Promise<void> {
try {
// Ensure directory exists
await ensureDir(this.tokenDir);
// Base64 encode for basic obfuscation
const encodedToken = btoa(token);
const filePath = this.getTokenPath(key);
// Write token to file
await Deno.writeTextFile(filePath, encodedToken);
// Set restrictive file permissions (Unix-like systems only)
if (Deno.build.os !== "windows") {
await Deno.chmod(filePath, 0o600); // Read/write for owner only
}
} catch (error: unknown) {
throw new Error(`Failed to store token: ${error instanceof Error ? error.message : String(error)}`);
}
}
async retrieve(key: string): Promise<string | null> {
try {
const filePath = this.getTokenPath(key);
const encodedToken = await Deno.readTextFile(filePath);
// Decode the token
const token = atob(encodedToken);
return token;
} catch (error: unknown) {
if (error instanceof Deno.errors.NotFound) {
console.log(`❌ Token not found: ${key}`);
return null;
}
throw new Error(`Failed to retrieve token: ${error instanceof Error ? error.message : String(error)}`);
}
}
async delete(key: string): Promise<boolean> {
try {
const filePath = this.getTokenPath(key);
await Deno.remove(filePath);
console.log(`✅ Token deleted: ${key}`);
return true;
} catch (error: unknown) {
if (error instanceof Deno.errors.NotFound) {
console.log(`❌ Token not found for deletion: ${key}`);
return false;
}
throw new Error(`Failed to delete token: ${error instanceof Error ? error.message : String(error)}`);
}
}
async exists(key: string): Promise<boolean> {
try {
const filePath = this.getTokenPath(key);
const stat = await Deno.stat(filePath);
return stat.isFile;
} catch {
return false;
}
}
async listTokens(): Promise<string[]> {
try {
const tokens: string[] = [];
for await (const entry of Deno.readDir(this.tokenDir)) {
if (entry.isFile && entry.name.endsWith('.token')) {
// Remove .token extension to get the key
const key = entry.name.replace('.token', '');
tokens.push(key);
}
}
return tokens;
} catch {
return [];
}
}
async clearAll(): Promise<number> {
try {
let count = 0;
for await (const entry of Deno.readDir(this.tokenDir)) {
if (entry.isFile && entry.name.endsWith('.token')) {
await Deno.remove(path.join(this.tokenDir, entry.name));
count++;
}
}
console.log(`✅ Cleared ${count} tokens`);
return count;
} catch {
return 0;
}
}
}
// Example usage
if (import.meta.main) {
const storage = new FileTokenStorage();
// Store some tokens
await storage.store("github_token", "ghp_1234567890abcdef");
await storage.store("api_key", "sk-proj-1234567890");
await storage.store("db_password", "super_secret_password");
// List all tokens
console.log("\nStored tokens:", await storage.listTokens());
// Retrieve a token
const githubToken = await storage.retrieve("github_token");
console.log("GitHub token:", githubToken);
// Check if token exists
const exists = await storage.exists("api_key");
console.log("API key exists:", exists);
// // Delete a token
// await storage.delete("db_password");
// // List remaining tokens
// console.log("Remaining tokens:", await storage.listTokens());
// // Clear all tokens
// await storage.clearAll();
}