229 lines
9.2 KiB
TypeScript
229 lines
9.2 KiB
TypeScript
import { Command } from "jsr:@cliffy/command@1.0.0-rc.7";
|
|
import { Secret } from "jsr:@cliffy/prompt@1.0.0-rc.7";
|
|
import { homedir } from "node:os";
|
|
import { TokenApi } from "./api/token-api.ts";
|
|
import { OAuth2Api } from "./api/oauth2-api.ts";
|
|
import { CredentialManager } from "./util/credential-manager.ts";
|
|
import { prettyOauth2Application, saveSecretKeys } from "./util/helpers.ts";
|
|
|
|
// Constants that were previously in types.ts
|
|
const URL_BASE = "https://git.monoid.top";
|
|
const TOKEN_NAME = "oauth2cli";
|
|
const CREDENTIALS_FILE = `${homedir()}/.oauth2cli-forgejo`;
|
|
|
|
async function main() {
|
|
const tokenApi = new TokenApi(URL_BASE, TOKEN_NAME);
|
|
const credentialManager = new CredentialManager(CREDENTIALS_FILE, TOKEN_NAME);
|
|
|
|
try {
|
|
await new Command()
|
|
.name("forgejo-oauth2cli")
|
|
.version("0.1.0")
|
|
.description("Interactive client credentials generator for Forgejo.")
|
|
.command("login", "Authenticate with Forgejo interactively")
|
|
.action(async() => {
|
|
const username = await prompt("Enter your username: ");
|
|
if (!username) {
|
|
console.error("Username is required.");
|
|
return;
|
|
}
|
|
|
|
const secret = await Secret.prompt("Enter your secret: ");
|
|
if (!secret) {
|
|
console.error("Secret is required.");
|
|
return;
|
|
}
|
|
|
|
// Check for existing tokens
|
|
const tokens = await tokenApi.listTokens(username, secret);
|
|
if (!tokens) {
|
|
return;
|
|
}
|
|
|
|
// Delete existing token if found
|
|
const existingToken = tokens.find(t => t.name === TOKEN_NAME);
|
|
if (existingToken) {
|
|
console.log("Existing token found, replacing it...");
|
|
await tokenApi.deleteToken(username, secret, existingToken.id);
|
|
}
|
|
|
|
// Create new token
|
|
console.log("Creating new token...");
|
|
const token = await tokenApi.createToken(username, secret);
|
|
if (!token) {
|
|
return;
|
|
}
|
|
|
|
// Store credentials
|
|
await credentialManager.storeCredentials(username, token.sha1);
|
|
console.log("Login successful! Credentials stored securely.");
|
|
})
|
|
.command("logout", "Delete token and credentials")
|
|
.action(async () => {
|
|
const username = await prompt("Enter your username: ");
|
|
if (!username) {
|
|
console.error("Username is required.");
|
|
return;
|
|
}
|
|
|
|
const secret = await Secret.prompt("Enter your secret: ");
|
|
if (!secret) {
|
|
console.error("Secret is required.");
|
|
return;
|
|
}
|
|
|
|
// Find and delete token
|
|
const tokens = await tokenApi.listTokens(username, secret);
|
|
if (!tokens) {
|
|
return;
|
|
}
|
|
|
|
const existingToken = tokens.find(t => t.name === TOKEN_NAME);
|
|
if (existingToken) {
|
|
await tokenApi.deleteToken(username, secret, existingToken.id);
|
|
console.log("Token deleted from Forgejo.");
|
|
}
|
|
|
|
// Clear stored credentials
|
|
await credentialManager.clearCredentials(username);
|
|
console.log("Logout successful! Credentials removed.");
|
|
})
|
|
.command("list, ls", "List all OAuth2 applications")
|
|
.action(async () => {
|
|
const credentials = await credentialManager.getCredentials();
|
|
if (!credentials) return;
|
|
|
|
// Create OAuth2Api with token
|
|
const oauth2Api = new OAuth2Api(URL_BASE, credentials.token);
|
|
const apps = await oauth2Api.getOauth2Applications();
|
|
if (!apps) return;
|
|
|
|
if (apps.length === 0) {
|
|
console.log("No OAuth2 applications found.");
|
|
return;
|
|
}
|
|
|
|
console.log("OAuth2 applications:");
|
|
console.log(apps.map(prettyOauth2Application).join("\n\n"));
|
|
})
|
|
.command("create", "Create new OAuth2 application")
|
|
.action(async () => {
|
|
const credentials = await credentialManager.getCredentials();
|
|
if (!credentials) return;
|
|
|
|
// Create OAuth2Api with token
|
|
const oauth2Api = new OAuth2Api(URL_BASE, credentials.token);
|
|
|
|
const name = await prompt("Enter the name of the application: ");
|
|
if (!name) {
|
|
console.error("Name is required.");
|
|
return;
|
|
}
|
|
|
|
const redirectUris = await prompt("Enter the redirect URIs (comma separated): ");
|
|
if (!redirectUris) {
|
|
console.error("Redirect URIs are required.");
|
|
return;
|
|
}
|
|
|
|
const app = await oauth2Api.createOauth2Application({
|
|
name,
|
|
redirect_uris: redirectUris.split(",").map(uri => uri.trim()),
|
|
});
|
|
|
|
if (!app) return;
|
|
|
|
console.log("OAuth2 application created successfully!");
|
|
console.log(prettyOauth2Application(app));
|
|
|
|
// Save secret keys
|
|
const path = await prompt("Enter the path to save the OAuth2 secret keys: ");
|
|
if (path) {
|
|
await saveSecretKeys(path, app.client_id, app.client_secret);
|
|
}
|
|
})
|
|
.command("delete", "Delete OAuth2 application")
|
|
.action(async () => {
|
|
const credentials = await credentialManager.getCredentials();
|
|
if (!credentials) return;
|
|
|
|
// Create OAuth2Api with token
|
|
const oauth2Api = new OAuth2Api(URL_BASE, credentials.token);
|
|
|
|
const id = await prompt("Enter the ID of the application to delete: ");
|
|
if (!id) {
|
|
console.error("ID is required.");
|
|
return;
|
|
}
|
|
|
|
const appId = parseInt(id);
|
|
if (isNaN(appId)) {
|
|
console.error("ID must be a number.");
|
|
return;
|
|
}
|
|
|
|
await oauth2Api.deleteOauth2Application(appId);
|
|
console.log("OAuth2 application deleted successfully!");
|
|
})
|
|
.command("update", "Update OAuth2 application")
|
|
.action(async () => {
|
|
const credentials = await credentialManager.getCredentials();
|
|
if (!credentials) return;
|
|
|
|
// Create OAuth2Api with token
|
|
const oauth2Api = new OAuth2Api(URL_BASE, credentials.token);
|
|
|
|
const id = await prompt("Enter the ID of the application to update: ");
|
|
if (!id) {
|
|
console.error("ID is required.");
|
|
return;
|
|
}
|
|
|
|
const appId = parseInt(id);
|
|
if (isNaN(appId)) {
|
|
console.error("ID must be a number.");
|
|
return;
|
|
}
|
|
|
|
const name = await prompt("Enter the new name of the application: ");
|
|
if (!name) {
|
|
console.error("Name is required.");
|
|
return;
|
|
}
|
|
|
|
const redirectUris = await prompt("Enter the new redirect URIs (comma separated): ");
|
|
if (!redirectUris) {
|
|
console.error("Redirect URIs are required.");
|
|
return;
|
|
}
|
|
|
|
const app = await oauth2Api.updateOauth2Application(appId, {
|
|
name,
|
|
redirect_uris: redirectUris.split(",").map(uri => uri.trim()),
|
|
});
|
|
|
|
if (!app) return;
|
|
|
|
console.log("OAuth2 application updated successfully!");
|
|
console.log(prettyOauth2Application(app));
|
|
|
|
// Save secret keys
|
|
const path = await prompt("Enter the path to save the OAuth2 secret keys: ");
|
|
if (path) {
|
|
await saveSecretKeys(path, app.client_id, app.client_secret);
|
|
}
|
|
})
|
|
.parse(Deno.args);
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
console.error("An error occurred:", error.message);
|
|
}
|
|
else {
|
|
console.error("An unexpected error occurred:", error);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
await main();
|
|
}
|