Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v4.0.0 #6

Merged
merged 6 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 38 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,53 @@

Simplify PGP key setup and signing commits on Linux and Windows.

## 📦 Usage
## 📦 Installation

```bash
# Using npx (recommended)
npx gitkeykit
```
or
```bash

# Or install globally
npm install -g gitkeykit
```

## Features
## 🚀 Usage

### Basic Setup
```bash
# Start the interactive setup
gitkeykit

- **Effortless PGP Key Management**: Create or import PGP keys with ease to secure your Git commits.
- **Cross-Platform Compatibility**: Works seamlessly on both Linux and Windows machines, ensuring a consistent experience across environments.
- **Git and GPG Configuration**: Automatically configure Git and GPG settings for seamless integration with your workflow.
- **Secure Passphrase Entry**: Enhance security with pinentry-mode loopback, ensuring passphrases are entered securely.
- **Fast and Efficient Operation**: Enjoy a lightning-fast CLI tool that gets the job done quickly and efficiently.
# Import existing PGP key
gitkeykit import my_key.txt

# Reset configurations
gitkeykit --reset

# Show version number
gitkeykit --version

# Display help information and available commands
gitkeykit --help
```

### Command Options
- `--reset` Reset Git and GPG configurations
- `--help` Show help information
- `--version` Show version number
- `--import <key_path.txt>` Import and configure PGP key from file

## ✨ Features

#### Options:
`--reset` Reset Git and GPG configurations
- **Interactive Setup**: Guided process for creating or importing PGP keys
- **Cross-Platform**: Works seamlessly on both Linux and Windows
- **Secure Configuration**:
- Automatic Git signing setup
- GPG agent configuration
- Secure passphrase handling
- **Error Handling**: Clear error messages and recovery options
- **Backup & Reset**: Automatic backup of existing configurations with reset capability

#### Commands:
`import <key_path.txt>` Import and set configuration with the provided PGP key

Examples:
`gitkeykit import my_key.txt` Import and set configuration with 'my_key.txt'
`gitkeykit --reset` Reset all configurations`
## 🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
96 changes: 48 additions & 48 deletions bin/index.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
#!/usr/bin/env node
import arg from "arg";
import chalk from "chalk";
import { fileURLToPath } from 'url';
import { fileURLToPath } from "url";
import { dirname, join } from "path";
import { readFileSync } from "fs";
import boxen from "boxen";
import { start } from "../src/commands/start";
import { reset } from "../src/commands/reset";
import { importKey } from "../src/commands/import";
import { GitKeyKitError, GitKeyKitCodes } from "../src/gitkeykitCodes";
import createLogger from "../src/utils/logger";
import boxen from 'boxen';
import { GitKeyKitCodes } from "../src/gitkeykitCodes";
import { dirname, join } from "path";
import { readFileSync } from "fs";

process.on("SIGINT", () => process.exit(GitKeyKitCodes.SUCCESS));
process.on("SIGTERM", () => process.exit(GitKeyKitCodes.SUCCESS));
const logger = createLogger("bin");

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const packageJson = JSON.parse(
readFileSync(join(__dirname, '../package.json'), 'utf8')
);
const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf8"));
const { version } = packageJson;

const logger = createLogger("bin");

function usage() {
console.log("\n");
console.log(chalk.blueBright(boxen('GitKeyKit - Simplify PGP key🔑 setup and signing commits on Linux and Windows machines.', {padding: 1, borderStyle: 'round'})));
console.log(chalk.blueBright(boxen("GitKeyKit - Simplify PGP key🔑 setup and signing commits on Linux and Windows machines.", { padding: 1, borderStyle: "round" })));
console.log(chalk.whiteBright("Usage: gitkeykit\n"));
console.log(chalk.whiteBright("Options:"));
console.log(chalk.blueBright("--reset\t\t\tReset Git and GPG configurations"));
Expand All @@ -43,85 +38,90 @@ function usage() {
console.log("\n");
}

async function handleImport(keyPath: string): Promise<number> {
async function handleImport(keyPath: string): Promise<void> {
try {
await importKey(keyPath);
logger.log(`Imported key from ${keyPath}`);
await start();
return GitKeyKitCodes.SUCCESS;
} catch (error) {
console.error(`Error importing key from ${keyPath}:`, error);
return GitKeyKitCodes.ERR_KEY_IMPORT;
if (error instanceof GitKeyKitError) {
throw error;
}
throw new GitKeyKitError(`Failed to import key from ${keyPath}`, GitKeyKitCodes.KEY_IMPORT_ERROR, error);
}
}

async function handleReset(): Promise<number> {
async function handleReset(): Promise<void> {
try {
reset();
return GitKeyKitCodes.SUCCESS;
} catch (error: any) {
logger.warning((error as Error).message);
console.log();
usage();
return GitKeyKitCodes.ERR_GIT_CONFIG_RESET;
await reset();
} catch (error) {
if (error instanceof GitKeyKitError) {
throw error;
}
throw new GitKeyKitError("Failed to reset configurations", GitKeyKitCodes.GIT_CONFIG_RESET_ERROR, error);
}
}

async function main(): Promise<number> {
async function main(): Promise<void> {
try {
const args = arg({
"--reset": Boolean,
"--help": Boolean,
"--import": String,
"--version": Boolean
"--version": Boolean,
});

logger.debug("Received args", args);

if (Object.keys(args).length === 1) {
await start();
return GitKeyKitCodes.SUCCESS;
return;
}

if (args["--reset"]) {
return handleReset();
await handleReset();
return;
}

if (args["--help"]) {
usage();
return GitKeyKitCodes.SUCCESS;
return;
}

if (args["--import"]) {
const keyPath = args["--import"];
return handleImport(keyPath);
await handleImport(keyPath);
return;
}

if (args["--version"]) {
console.log(`v${version}`);
return GitKeyKitCodes.SUCCESS;
return;
}

usage();
return GitKeyKitCodes.ERR_INVALID_ARGS;
} catch (error: any) {
if (error?.code === 'ARG_UNKNOWN_OPTION') {
} catch (error) {
if (error instanceof arg.ArgError && error?.code === "ARG_UNKNOWN_OPTION") {
logger.error(`Invalid argument: ${error.message}`);
console.log('------');
console.log("------");
usage();
return GitKeyKitCodes.ERR_INVALID_ARGS;
process.exit(1);
}

if (error instanceof GitKeyKitError) {
logger.error(`Error: ${error.message} (${error.code})`);
if (error.details) {
logger.debug("Error details:", error.details);
}
process.exit(1);
}

// Handle any other unexpected errors
logger.error('An unexpected error occurred:', error);
return GitKeyKitCodes.ERR_INVALID_ARGS;

logger.error("An unexpected error occurred:", error);
process.exit(1);
}
}

// Execute and handle exit codes
main()
.then(exitCode => process.exit(exitCode))
.catch(error => {
console.error('Unexpected error:', error);
process.exit(1);
});
main().catch((error) => {
logger.error("Fatal error:", error);
process.exit(1);
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gitkeykit",
"version": "3.0.0",
"version": "4.0.0-next.1",
"description": "Setup pgp keys and sign commits with ease on Linux and Windows machines.",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
Expand Down
44 changes: 38 additions & 6 deletions src/commands/import.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
import { readFileSync } from "fs";
import { execSync } from "child_process";
import { GitKeyKitCodes, GitKeyKitError } from "../gitkeykitCodes";
import createLogger from "../utils/logger";

export function importKey(key: string): boolean {
const logger = createLogger("commands:import");

/**
* Imports a GPG key from a file
* @param keyPath Path to the key file
* @throws {GitKeyKitError} If key import fails
*/
export async function importKey(keyPath: string): Promise<void> {
try {
execSync(`gpg --import ${key}`, { stdio: "inherit" });
return true; // Indicate success
} catch (error: any) {
throw new Error(`Error importing key: ${(error as Error).message}`);
let keyContent: string;
try {
keyContent = readFileSync(keyPath, "utf-8");
} catch (error) {
throw new GitKeyKitError(`Failed to read key file: ${keyPath}`, GitKeyKitCodes.KEY_IMPORT_ERROR, error);
}

if (!keyContent.includes("-----BEGIN PGP PRIVATE KEY BLOCK-----")) {
throw new GitKeyKitError("Invalid key file format: Missing PGP private key block", GitKeyKitCodes.KEY_IMPORT_ERROR);
}

try {
execSync("gpg --import", {
input: keyContent,
stdio: ["pipe", "inherit", "inherit"],
});

logger.green("GPG key imported successfully");
} catch (error) {
throw new GitKeyKitError("Failed to import GPG key", GitKeyKitCodes.KEY_IMPORT_ERROR, error);
}
} catch (error) {
if (error instanceof GitKeyKitError) {
throw error;
}
throw new GitKeyKitError("Unexpected error during key import", GitKeyKitCodes.KEY_IMPORT_ERROR, error);
}
}
}
Loading
Loading