@deploily/deploily-cli 0.1.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.
Files changed (46) hide show
  1. package/.devcontainer/devcontainer.json +25 -0
  2. package/.devcontainer/docker-compose.yml +18 -0
  3. package/.env.example +8 -0
  4. package/.github/dependabot.yml +12 -0
  5. package/.github/workflows/publish.yml +39 -0
  6. package/LICENSE +201 -0
  7. package/README.md +105 -0
  8. package/dist/auth/callback.d.ts +3 -0
  9. package/dist/auth/callback.d.ts.map +1 -0
  10. package/dist/auth/callback.js +143 -0
  11. package/dist/auth/callback.js.map +1 -0
  12. package/dist/auth/index.d.ts +23 -0
  13. package/dist/auth/index.d.ts.map +1 -0
  14. package/dist/auth/index.js +173 -0
  15. package/dist/auth/index.js.map +1 -0
  16. package/dist/commands/auth.d.ts +4 -0
  17. package/dist/commands/auth.d.ts.map +1 -0
  18. package/dist/commands/auth.js +90 -0
  19. package/dist/commands/auth.js.map +1 -0
  20. package/dist/config/constants.d.ts +22 -0
  21. package/dist/config/constants.d.ts.map +1 -0
  22. package/dist/config/constants.js +25 -0
  23. package/dist/config/constants.js.map +1 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +61 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/storage/credentials.d.ts +47 -0
  29. package/dist/storage/credentials.d.ts.map +1 -0
  30. package/dist/storage/credentials.js +160 -0
  31. package/dist/storage/credentials.js.map +1 -0
  32. package/dist/utils/pkce.d.ts +5 -0
  33. package/dist/utils/pkce.d.ts.map +1 -0
  34. package/dist/utils/pkce.js +30 -0
  35. package/dist/utils/pkce.js.map +1 -0
  36. package/package.json +37 -0
  37. package/pnpm-workspace.yaml +5 -0
  38. package/src/auth/callback.ts +159 -0
  39. package/src/auth/index.ts +238 -0
  40. package/src/commands/auth.ts +114 -0
  41. package/src/config/constants.ts +28 -0
  42. package/src/index.ts +69 -0
  43. package/src/storage/credentials.ts +188 -0
  44. package/src/types/index.d.ts +35 -0
  45. package/src/utils/pkce.ts +36 -0
  46. package/tsconfig.json +24 -0
@@ -0,0 +1,173 @@
1
+ import axios from "axios";
2
+ import { generateCodeVerifier, generateCodeChallenge, generateState, } from "../utils/pkce.js";
3
+ import { AUTH_CONFIG } from "../config/constants.js";
4
+ import { credentialStorage } from "../storage/credentials.js";
5
+ class AuthenticationService {
6
+ constructor() {
7
+ this.client = axios.create({
8
+ timeout: 10000,
9
+ });
10
+ }
11
+ buildClientAuthHeaders() {
12
+ const clientSecret = process.env.KEYCLOAK_CLIENT_SECRET;
13
+ if (!clientSecret) {
14
+ return {};
15
+ }
16
+ const clientId = process.env.KEYCLOAK_CLIENT_ID;
17
+ const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
18
+ return {
19
+ Authorization: `Basic ${basicAuth}`,
20
+ };
21
+ }
22
+ // Generate authorization URL for user login
23
+ generateAuthorizationUrl() {
24
+ const state = generateState();
25
+ const codeVerifier = generateCodeVerifier();
26
+ const codeChallenge = generateCodeChallenge(codeVerifier);
27
+ const params = new URLSearchParams({
28
+ client_id: AUTH_CONFIG.CLIENT_ID,
29
+ response_type: AUTH_CONFIG.RESPONSE_TYPE,
30
+ redirect_uri: AUTH_CONFIG.REDIRECT_URI,
31
+ scope: AUTH_CONFIG.SCOPE,
32
+ code_challenge: codeChallenge,
33
+ code_challenge_method: AUTH_CONFIG.CODE_CHALLENGE_METHOD,
34
+ state,
35
+ });
36
+ const url = `${AUTH_CONFIG.KEYCLOAK_AUTH_ENDPOINT}?${params.toString()}`;
37
+ return {
38
+ url,
39
+ context: { state, codeVerifier, codeChallenge },
40
+ };
41
+ }
42
+ // Exchange authorization code for tokens
43
+ async exchangeCodeForToken(code, codeVerifier) {
44
+ try {
45
+ const body = new URLSearchParams({
46
+ grant_type: "authorization_code",
47
+ code,
48
+ client_id: process.env.KEYCLOAK_CLIENT_ID,
49
+ redirect_uri: process.env.KEYCLOAK_REDIRECT_URI,
50
+ code_verifier: codeVerifier,
51
+ });
52
+ const response = await this.client.post(process.env.KEYCLOAK_TOKEN_ENDPOINT, body, {
53
+ headers: {
54
+ "Content-Type": "application/x-www-form-urlencoded",
55
+ ...this.buildClientAuthHeaders(),
56
+ },
57
+ });
58
+ return response.data;
59
+ }
60
+ catch (error) {
61
+ if (axios.isAxiosError(error)) {
62
+ const responseData = typeof error.response?.data === "string"
63
+ ? error.response.data
64
+ : JSON.stringify(error.response?.data ?? {});
65
+ const authHint = error.response?.status === 401 &&
66
+ responseData.includes("unauthorized_client")
67
+ ? " This usually means the Keycloak client is confidential and KEYCLOAK_CLIENT_SECRET is missing or invalid."
68
+ : "";
69
+ throw new Error(`Failed to exchange code for token: ${error.message}${responseData ? ` (${responseData})` : ""}${authHint}`);
70
+ }
71
+ throw new Error(`Failed to exchange code for token: ${error instanceof Error ? error.message : "Unknown error"}`);
72
+ }
73
+ }
74
+ // Refresh access token using refresh token
75
+ async refreshAccessToken(refreshToken) {
76
+ try {
77
+ const body = new URLSearchParams({
78
+ grant_type: "refresh_token",
79
+ refresh_token: refreshToken,
80
+ client_id: process.env.KEYCLOAK_CLIENT_ID,
81
+ });
82
+ const response = await this.client.post(process.env.KEYCLOAK_TOKEN_ENDPOINT, body, {
83
+ headers: {
84
+ "Content-Type": "application/x-www-form-urlencoded",
85
+ ...this.buildClientAuthHeaders(),
86
+ },
87
+ });
88
+ return response.data;
89
+ }
90
+ catch (error) {
91
+ throw new Error(`Failed to refresh token: ${error instanceof Error ? error.message : "Unknown error"}`);
92
+ }
93
+ }
94
+ // Get user information from access token
95
+ async getUserInfo(accessToken) {
96
+ try {
97
+ const response = await this.client.get(process.env.KEYCLOAK_USERINFO_ENDPOINT, {
98
+ headers: {
99
+ Authorization: `Bearer ${accessToken}`,
100
+ },
101
+ });
102
+ return response.data;
103
+ }
104
+ catch (error) {
105
+ throw new Error(`Failed to fetch user info: ${error instanceof Error ? error.message : "Unknown error"}`);
106
+ }
107
+ }
108
+ // Store tokens after successful authentication
109
+ async storeTokens(token, userEmail) {
110
+ const expiresAt = Math.floor(Date.now() / 1000) + token.expires_in;
111
+ const credentials = {
112
+ access_token: token.access_token,
113
+ refresh_token: token.refresh_token,
114
+ expires_at: expiresAt,
115
+ user_email: userEmail,
116
+ };
117
+ await credentialStorage.save(credentials);
118
+ }
119
+ // Get valid access token
120
+ async getValidAccessToken() {
121
+ const credentials = await credentialStorage.load();
122
+ if (!credentials) {
123
+ return null;
124
+ }
125
+ // Check if token is expired
126
+ if (credentials.expires_at < Date.now() / 1000) {
127
+ try {
128
+ const newToken = await this.refreshAccessToken(credentials.refresh_token);
129
+ await this.storeTokens(newToken, credentials.user_email);
130
+ return newToken.access_token;
131
+ }
132
+ catch (error) {
133
+ // Token refresh failed, need to re-authenticate
134
+ await credentialStorage.clear();
135
+ return null;
136
+ }
137
+ }
138
+ return credentials.access_token;
139
+ }
140
+ // Logout and clear stored tokens
141
+ async logout() {
142
+ const credentials = await credentialStorage.load();
143
+ if (credentials) {
144
+ try {
145
+ const body = new URLSearchParams({
146
+ client_id: process.env.KEYCLOAK_CLIENT_ID,
147
+ refresh_token: credentials.refresh_token,
148
+ });
149
+ // Optionally call Keycloak logout endpoint
150
+ await this.client.post(process.env.KEYCLOAK_LOGOUT_ENDPOINT, body, {
151
+ headers: {
152
+ "Content-Type": "application/x-www-form-urlencoded",
153
+ ...this.buildClientAuthHeaders(),
154
+ },
155
+ });
156
+ }
157
+ catch (error) {
158
+ // Continue with local logout even if server call fails
159
+ }
160
+ }
161
+ // Clear local credentials
162
+ await credentialStorage.clear();
163
+ }
164
+ /**
165
+ * Check if user is authenticated
166
+ */
167
+ async isAuthenticated() {
168
+ const credentials = await credentialStorage.load();
169
+ return credentials !== null;
170
+ }
171
+ }
172
+ export const authService = new AuthenticationService();
173
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function handleLogin(): Promise<void>;
2
+ export declare function handleLogout(): Promise<void>;
3
+ export declare function handleWhoami(): Promise<void>;
4
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAMA,wBAAsB,WAAW,kBAyChC;AAED,wBAAsB,YAAY,kBAejC;AAED,wBAAsB,YAAY,kBA+CjC"}
@@ -0,0 +1,90 @@
1
+ import open from "open";
2
+ import { authService } from "../auth/index.js";
3
+ import { startCallbackServer } from "../auth/callback.js";
4
+ import { credentialStorage } from "../storage/credentials.js";
5
+ import chalk from "chalk";
6
+ export async function handleLogin() {
7
+ try {
8
+ // 1. Check if logged in
9
+ const isAuth = await authService.isAuthenticated();
10
+ if (isAuth) {
11
+ console.log("Already logged in. Use 'deploily logout' to log out first.");
12
+ return;
13
+ }
14
+ console.log("Opening browser for authentication...");
15
+ // 2. Generate authorization URL
16
+ const { url, context } = authService.generateAuthorizationUrl();
17
+ // 3. Start callback server
18
+ const callbackPromise = startCallbackServer(context.state);
19
+ // 4. Open browser
20
+ await open(url);
21
+ console.log("Waiting for authentication...");
22
+ // 5. Wait for callback
23
+ const callback = await callbackPromise;
24
+ // 6. Exchange code for token
25
+ const tokens = await authService.exchangeCodeForToken(callback.code, context.codeVerifier);
26
+ // 7. Get user info
27
+ const userInfo = await authService.getUserInfo(tokens.access_token);
28
+ // 8. Store tokens
29
+ await authService.storeTokens(tokens, userInfo.email);
30
+ console.log("Successfully authenticated");
31
+ console.log(`Welcome, ${userInfo.email}!`);
32
+ }
33
+ catch (error) {
34
+ console.error("Error occurred while logging in:", error);
35
+ process.exit(1);
36
+ }
37
+ }
38
+ export async function handleLogout() {
39
+ try {
40
+ const isAuth = await authService.isAuthenticated();
41
+ if (!isAuth) {
42
+ console.log("You are not logged in.");
43
+ return;
44
+ }
45
+ await authService.logout();
46
+ console.log("Successfully logged out");
47
+ }
48
+ catch (error) {
49
+ console.error("Error occurred while logging in:", error);
50
+ process.exit(1);
51
+ }
52
+ }
53
+ export async function handleWhoami() {
54
+ try {
55
+ const isAuth = await authService.isAuthenticated();
56
+ if (!isAuth) {
57
+ console.log("You are not logged in. Use `deploily login` to authenticate.");
58
+ process.exit(1);
59
+ }
60
+ // Get stored credentials
61
+ const credentials = await credentialStorage.load();
62
+ if (!credentials) {
63
+ console.log("You are not logged in. Use `deploily login` to authenticate.");
64
+ process.exit(1);
65
+ }
66
+ // Get user info from API
67
+ const userInfo = await authService.getUserInfo(credentials.access_token);
68
+ console.log("Current User:");
69
+ console.log(`├─ Email: ${userInfo.email}`);
70
+ console.log(`├─ Name: ${userInfo.name}`);
71
+ console.log(`├─ Username: ${userInfo.preferred_username}`);
72
+ // Calculate token expiry
73
+ const expiresAt = new Date(credentials.expires_at * 1000);
74
+ const now = new Date();
75
+ const timeRemaining = Math.floor((credentials.expires_at * 1000 - now.getTime()) / 1000);
76
+ if (timeRemaining > 0) {
77
+ const hours = Math.floor(timeRemaining / 3600);
78
+ const minutes = Math.floor((timeRemaining % 3600) / 60);
79
+ console.log(chalk.gray(`└─ Token expires in: ${hours}h ${minutes}m`));
80
+ }
81
+ else {
82
+ console.log(chalk.gray(`└─ Token expires in: Soon (will auto-refresh)`));
83
+ }
84
+ }
85
+ catch (error) {
86
+ console.error("Error occurred while logging in:", error);
87
+ process.exit(1);
88
+ }
89
+ }
90
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import "dotenv/config";
2
+ export declare const AUTH_CONFIG: {
3
+ KEYCLOAK_REALM_URL: string;
4
+ KEYCLOAK_TOKEN_ENDPOINT: string;
5
+ KEYCLOAK_AUTH_ENDPOINT: string;
6
+ KEYCLOAK_LOGOUT_ENDPOINT: string;
7
+ KEYCLOAK_USERINFO_ENDPOINT: string;
8
+ CLIENT_ID: string;
9
+ CLIENT_SECRET: string;
10
+ REDIRECT_URI: string;
11
+ CALLBACK_PORT: number;
12
+ SCOPE: string;
13
+ RESPONSE_TYPE: string;
14
+ CODE_CHALLENGE_METHOD: string;
15
+ TOKEN_EXPIRY_BUFFER: number;
16
+ };
17
+ export declare const STORAGE_CONFIG: {
18
+ SERVICE_NAME: string;
19
+ CONFIG_DIR: string;
20
+ CONFIG_FILE: string;
21
+ };
22
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/config/constants.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAEtB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;CAmBvB,CAAA;AAED,eAAO,MAAM,cAAc;;;;CAI1B,CAAA"}
@@ -0,0 +1,25 @@
1
+ import "dotenv/config";
2
+ export const AUTH_CONFIG = {
3
+ // Keycloak Configuration
4
+ KEYCLOAK_REALM_URL: process.env.KEYCLOAK_REALM_URL,
5
+ KEYCLOAK_TOKEN_ENDPOINT: process.env.KEYCLOAK_TOKEN_ENDPOINT,
6
+ KEYCLOAK_AUTH_ENDPOINT: process.env.KEYCLOAK_AUTH_ENDPOINT,
7
+ KEYCLOAK_LOGOUT_ENDPOINT: process.env.KEYCLOAK_LOGOUT_ENDPOINT,
8
+ KEYCLOAK_USERINFO_ENDPOINT: process.env.KEYCLOAK_USERINFO_ENDPOINT,
9
+ // CLI Configuration
10
+ CLIENT_ID: process.env.KEYCLOAK_CLIENT_ID,
11
+ CLIENT_SECRET: process.env.KEYCLOAK_CLIENT_SECRET,
12
+ REDIRECT_URI: process.env.KEYCLOAK_REDIRECT_URI,
13
+ CALLBACK_PORT: 8976,
14
+ SCOPE: "openid profile email",
15
+ RESPONSE_TYPE: "code",
16
+ CODE_CHALLENGE_METHOD: "S256",
17
+ // Token Configuration
18
+ TOKEN_EXPIRY_BUFFER: 60,
19
+ };
20
+ export const STORAGE_CONFIG = {
21
+ SERVICE_NAME: "deploily-cli",
22
+ CONFIG_DIR: "~/.config/deploily",
23
+ CONFIG_FILE: "config.json",
24
+ };
25
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/config/constants.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAEtB,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,yBAAyB;IACzB,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAmB;IACnD,uBAAuB,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAwB;IAC7D,sBAAsB,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAuB;IAC3D,wBAAwB,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAyB;IAC/D,0BAA0B,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA2B;IAEnE,oBAAoB;IACpB,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAmB;IAC1C,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAuB;IAClD,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAsB;IAChD,aAAa,EAAE,IAAI;IACnB,KAAK,EAAE,sBAAsB;IAC7B,aAAa,EAAE,MAAM;IACrB,qBAAqB,EAAE,MAAM;IAE7B,sBAAsB;IACtB,mBAAmB,EAAE,EAAE;CACxB,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,YAAY,EAAE,cAAc;IAC5B,UAAU,EAAE,oBAAoB;IAChC,WAAW,EAAE,aAAa;CAC3B,CAAA"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ import { handleLogin, handleLogout, handleWhoami } from "./commands/auth.js";
3
+ const VERSION = "1.0.0"; // TODO: read from package.json
4
+ async function main() {
5
+ const args = process.argv.slice(2);
6
+ const command = args[0];
7
+ if (!command || command === "--help" || command === "-h") {
8
+ showHelp();
9
+ return;
10
+ }
11
+ if (command === "--version" || command === "-v") {
12
+ console.log(`deploily version ${VERSION}`);
13
+ return;
14
+ }
15
+ try {
16
+ switch (command) {
17
+ case "login":
18
+ await handleLogin();
19
+ break;
20
+ case "logout":
21
+ await handleLogout();
22
+ break;
23
+ case "whoami":
24
+ await handleWhoami();
25
+ break;
26
+ default:
27
+ console.error(`Unknown command: ${command}`);
28
+ showHelp();
29
+ process.exit(1);
30
+ }
31
+ }
32
+ catch (err) {
33
+ console.error(`Error executing command '${command}':`, err);
34
+ process.exit(1);
35
+ }
36
+ }
37
+ function showHelp() {
38
+ console.log(`
39
+ Usage:
40
+ deploily [command]
41
+
42
+ Commands:
43
+ login Authenticate with Keycloak
44
+ logout Clear authentication tokens
45
+ whoami Show current user information
46
+
47
+ Options:
48
+ --help, -h Show this help message
49
+ --version Show version number
50
+
51
+ Examples:
52
+ deploily login
53
+ deploily logout
54
+ deploily whoami
55
+ `);
56
+ }
57
+ main().catch((err) => {
58
+ console.error(err);
59
+ process.exit(1);
60
+ });
61
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAE5E,MAAM,OAAO,GAAG,OAAO,CAAA,CAAC,+BAA+B;AAEvD,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAClC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;IAEvB,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACzD,QAAQ,EAAE,CAAA;QACV,OAAM;IACR,CAAC;IAED,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAA;QAC1C,OAAM;IACR,CAAC;IAED,IAAI,CAAC;QACH,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,OAAO;gBACV,MAAM,WAAW,EAAE,CAAA;gBACnB,MAAK;YAEP,KAAK,QAAQ;gBACX,MAAM,YAAY,EAAE,CAAA;gBACpB,MAAK;YAEP,KAAK,QAAQ;gBACX,MAAM,YAAY,EAAE,CAAA;gBACpB,MAAK;YAEP;gBACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAA;gBAC5C,QAAQ,EAAE,CAAA;gBACV,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,OAAO,IAAI,EAAE,GAAG,CAAC,CAAA;QAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;CAiBb,CAAC,CAAA;AACF,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
@@ -0,0 +1,47 @@
1
+ import { StoredCredentials } from "../types/index.js";
2
+ declare class CredentialStorage {
3
+ private serviceName;
4
+ private accountName;
5
+ private configDir;
6
+ private configFilePath;
7
+ constructor();
8
+ /**
9
+ * Expand ~ to home directory
10
+ */
11
+ private expandPath;
12
+ /**
13
+ * Save credentials using keytar (primary) or fallback to config file
14
+ */
15
+ save(credentials: StoredCredentials): Promise<void>;
16
+ /**
17
+ * Load credentials using keytar (primary) or fallback to config file
18
+ */
19
+ load(): Promise<StoredCredentials | null>;
20
+ /**
21
+ * Clear credentials from keytar (primary) and config file
22
+ */
23
+ clear(): Promise<void>;
24
+ /**
25
+ * Save to config file (fallback method)
26
+ */
27
+ private saveToConfigFile;
28
+ /**
29
+ * Load from config file (fallback method)
30
+ */
31
+ private loadFromConfigFile;
32
+ /**
33
+ * Clear config file
34
+ */
35
+ private clearConfigFile;
36
+ /**
37
+ * Check if credentials exist
38
+ */
39
+ exists(): Promise<boolean>;
40
+ /**
41
+ * Check if credentials are expired
42
+ */
43
+ isExpired(): Promise<boolean>;
44
+ }
45
+ export declare const credentialStorage: CredentialStorage;
46
+ export {};
47
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/storage/credentials.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAoBrD,cAAM,iBAAiB;IACrB,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,cAAc,CAAQ;;IAO9B;;OAEG;IACH,OAAO,CAAC,UAAU;IAOlB;;OAEG;IACG,IAAI,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBzD;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAsB/C;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B;;OAEG;YACW,gBAAgB;IAmB9B;;OAEG;YACW,kBAAkB;IAahC;;OAEG;YACW,eAAe;IAU7B;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAKhC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAUpC;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAA"}
@@ -0,0 +1,160 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import os from "os";
4
+ import { STORAGE_CONFIG } from "../config/constants.js";
5
+ // Lazy load keytar - it's optional and may not be available
6
+ let keytar = null;
7
+ let keytarLoaded = false;
8
+ async function getKeytar() {
9
+ if (keytarLoaded) {
10
+ return keytar;
11
+ }
12
+ keytarLoaded = true;
13
+ try {
14
+ keytar = await import("keytar");
15
+ }
16
+ catch (error) {
17
+ // keytar not available, will use fallback
18
+ keytar = null;
19
+ }
20
+ return keytar;
21
+ }
22
+ class CredentialStorage {
23
+ constructor() {
24
+ this.serviceName = STORAGE_CONFIG.SERVICE_NAME;
25
+ this.accountName = "deploily-auth";
26
+ this.configDir = this.expandPath(STORAGE_CONFIG.CONFIG_DIR);
27
+ this.configFilePath = path.join(this.configDir, STORAGE_CONFIG.CONFIG_FILE);
28
+ }
29
+ /**
30
+ * Expand ~ to home directory
31
+ */
32
+ expandPath(filepath) {
33
+ if (filepath.startsWith("~")) {
34
+ return path.join(os.homedir(), filepath.slice(1));
35
+ }
36
+ return filepath;
37
+ }
38
+ /**
39
+ * Save credentials using keytar (primary) or fallback to config file
40
+ */
41
+ async save(credentials) {
42
+ const kt = await getKeytar();
43
+ try {
44
+ // Try keytar first
45
+ if (kt) {
46
+ await kt.setPassword(this.serviceName, this.accountName, JSON.stringify(credentials));
47
+ return;
48
+ }
49
+ }
50
+ catch (error) {
51
+ // Fallback to config file
52
+ }
53
+ // Fallback to config file
54
+ console.warn("Keytar unavailable, using config file for token storage");
55
+ await this.saveToConfigFile(credentials);
56
+ }
57
+ /**
58
+ * Load credentials using keytar (primary) or fallback to config file
59
+ */
60
+ async load() {
61
+ const kt = await getKeytar();
62
+ try {
63
+ // Try keytar first
64
+ if (kt) {
65
+ const password = await kt.getPassword(this.serviceName, this.accountName);
66
+ if (password) {
67
+ return JSON.parse(password);
68
+ }
69
+ }
70
+ }
71
+ catch (error) {
72
+ // Fallback to config file
73
+ console.warn("Keytar unavailable, checking config file");
74
+ }
75
+ // Try loading from config file
76
+ return await this.loadFromConfigFile();
77
+ }
78
+ /**
79
+ * Clear credentials from keytar (primary) and config file
80
+ */
81
+ async clear() {
82
+ const kt = await getKeytar();
83
+ try {
84
+ // Clear from keytar
85
+ if (kt) {
86
+ await kt.deletePassword(this.serviceName, this.accountName);
87
+ }
88
+ }
89
+ catch (error) {
90
+ // Fallback to config file
91
+ console.warn("Could not clear keytar credentials");
92
+ }
93
+ // Clear from config file
94
+ await this.clearConfigFile();
95
+ }
96
+ /**
97
+ * Save to config file (fallback method)
98
+ */
99
+ async saveToConfigFile(credentials) {
100
+ try {
101
+ // Ensure config directory exists
102
+ if (!fs.existsSync(this.configDir)) {
103
+ fs.mkdirSync(this.configDir, { recursive: true });
104
+ }
105
+ fs.writeFileSync(this.configFilePath, JSON.stringify(credentials, null, 2), { mode: 0o600 });
106
+ }
107
+ catch (error) {
108
+ throw new Error(`Failed to save credentials: ${error}`);
109
+ }
110
+ }
111
+ /**
112
+ * Load from config file (fallback method)
113
+ */
114
+ async loadFromConfigFile() {
115
+ try {
116
+ if (!fs.existsSync(this.configFilePath)) {
117
+ return null;
118
+ }
119
+ const content = fs.readFileSync(this.configFilePath, "utf-8");
120
+ return JSON.parse(content);
121
+ }
122
+ catch (error) {
123
+ return null;
124
+ }
125
+ }
126
+ /**
127
+ * Clear config file
128
+ */
129
+ async clearConfigFile() {
130
+ try {
131
+ if (fs.existsSync(this.configFilePath)) {
132
+ fs.unlinkSync(this.configFilePath);
133
+ }
134
+ }
135
+ catch (error) {
136
+ // Silently fail if file doesn't exist
137
+ }
138
+ }
139
+ /**
140
+ * Check if credentials exist
141
+ */
142
+ async exists() {
143
+ const credentials = await this.load();
144
+ return credentials !== null;
145
+ }
146
+ /**
147
+ * Check if credentials are expired
148
+ */
149
+ async isExpired() {
150
+ const credentials = await this.load();
151
+ if (!credentials) {
152
+ return true;
153
+ }
154
+ // Check if token expires in less than 5 minutes
155
+ const bufferSeconds = 300;
156
+ return credentials.expires_at < Date.now() / 1000 + bufferSeconds;
157
+ }
158
+ }
159
+ export const credentialStorage = new CredentialStorage();
160
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/storage/credentials.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function generateRandomString(length?: number): string;
2
+ export declare function generateCodeVerifier(): string;
3
+ export declare function generateCodeChallenge(codeVerifier: string): string;
4
+ export declare function generateState(): string;
5
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../src/utils/pkce.ts"],"names":[],"mappings":"AAGA,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,MAAW,GAAG,MAAM,CAEhE;AAGD,wBAAgB,oBAAoB,IAAI,MAAM,CAY7C;AAGD,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAOlE;AAGD,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}