Metadata-Version: 2.4
Name: npp-secrets
Version: 1.0.0
Summary: Python library to access Notepad++ Secrets Manager encrypted secrets
Author-email: Art Le Bel <artofscripting@gmail.com>
License: GPL-2.0-or-later
Project-URL: Homepage, https://github.com/artofscripting/npp-secrets
Project-URL: Documentation, https://github.com/artofscripting/npp-secrets#readme
Project-URL: Repository, https://github.com/artofscripting/npp-secrets
Project-URL: Bug Tracker, https://github.com/artofscripting/npp-secrets/issues
Keywords: notepad++,secrets,encryption,dpapi,password-manager
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Requires-Dist: pywin32>=300
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=3.0; extra == "dev"
Requires-Dist: black>=22.0; extra == "dev"
Requires-Dist: mypy>=0.950; extra == "dev"
Requires-Dist: flake8>=4.0; extra == "dev"

# Notepad++ Secrets Manager - Python Library

A Python library to access secrets stored by the [Notepad++ Secrets Manager plugin](../). Read encrypted secrets directly from Python scripts without opening Notepad++.

## Features

- ✅ **Read encrypted secrets** - Access secrets stored by Notepad++ plugin
- ✅ **Password protected** - Verifies master password using SHA-256
- ✅ **Strong encryption** - Uses PBKDF2 + Windows DPAPI (same as C++ plugin)
- ✅ **Simple API** - Easy-to-use Python interface
- ✅ **Type hints** - Full type annotations for better IDE support
- ✅ **Search & filter** - Find secrets by name or category
- ✅ **Environment variables** - Export secrets as env vars

## Installation

### From PyPI

```bash
pip install npp-secrets
```

### From source

```bash
cd python_library
pip install .
```

### Development install

```bash
cd python_library
pip install -e ".[dev]"
```

## Requirements

- **Python 3.7+**
- **Windows** (uses Windows DPAPI)
- **pywin32** - For Windows Cryptography API access

## Quick Start

### Basic Usage

```python
from npp_secrets import SecretsManager

# Initialize manager
manager = SecretsManager()

# Check if password is set
if manager.has_password():
    # Unlock with your master password
    manager.unlock("your_master_password")
    
    # Get a specific secret
    api_key = manager.get_secret("GitHub API Key")
    print(f"API Key: {api_key}")
    
    # List all secrets
    for secret in manager.list_secrets():
        print(f"{secret.name}: {secret.value}")
    
    # Lock when done
    manager.lock()
```

### Using as Environment Variables

```python
from npp_secrets import SecretsManager
import os

manager = SecretsManager()
manager.unlock("your_password")

# Get secrets as environment variables
env_vars = manager.get_as_env_dict()
os.environ.update(env_vars)

# Now use them
github_token = os.environ["GITHUB_API_KEY"]  # From "GitHub API Key"
```

### Search and Filter

```python
from npp_secrets import SecretsManager

manager = SecretsManager()
manager.unlock("your_password")

# Search by name
results = manager.search_secrets("github")
for secret in results:
    print(f"Found: {secret.name}")

# Get secrets by category
api_keys = manager.get_secret_by_category("API Keys")
for secret in api_keys:
    print(f"{secret.name} = {secret.value}")
```

### Error Handling

```python
from npp_secrets import (
    SecretsManager, 
    InvalidPasswordError, 
    SecretsFileNotFoundError,
    SecretsManagerError
)

manager = SecretsManager()

try:
    manager.unlock("wrong_password")
except InvalidPasswordError:
    print("Incorrect password!")
except SecretsFileNotFoundError:
    print("Secrets file not found. Create secrets in Notepad++ first.")
except SecretsManagerError as e:
    print(f"Error: {e}")
```

### Context Manager (Future)

```python
from npp_secrets import SecretsManager

# Automatically locks when exiting context
with SecretsManager() as manager:
    manager.unlock("your_password")
    api_key = manager.get_secret("My API Key")
    # Use the API key...
# Automatically locked here
```

## API Reference

### `SecretsManager`

#### Methods

##### `__init__(config_dir: Optional[str] = None)`
Initialize the secrets manager.

**Parameters:**
- `config_dir` (optional): Custom config directory. Defaults to `%APPDATA%\Notepad++\plugins\config`

##### `has_password() -> bool`
Check if a master password has been set.

**Returns:** `True` if password exists, `False` otherwise

##### `verify_password(password: str) -> bool`
Verify if the provided password is correct.

**Parameters:**
- `password`: Password to verify

**Returns:** `True` if correct, `False` otherwise

##### `unlock(password: str) -> None`
Unlock the secrets manager.

**Parameters:**
- `password`: Master password

**Raises:**
- `InvalidPasswordError`: If password is incorrect
- `SecretsFileNotFoundError`: If secrets file doesn't exist

##### `lock() -> None`
Lock the secrets manager and clear secrets from memory.

##### `get_secret(name: str) -> Optional[str]`
Get a secret by name.

**Parameters:**
- `name`: Secret name

**Returns:** Secret value or `None` if not found

**Raises:**
- `SecretsManagerError`: If not unlocked

##### `get_secret_by_category(category: str) -> List[Secret]`
Get all secrets in a category.

**Parameters:**
- `category`: Category name

**Returns:** List of secrets

##### `list_secrets() -> List[Secret]`
Get all secrets.

**Returns:** List of all secrets

##### `search_secrets(query: str) -> List[Secret]`
Search secrets by name (case-insensitive).

**Parameters:**
- `query`: Search query

**Returns:** List of matching secrets

##### `get_as_dict() -> Dict[str, str]`
Get all secrets as a dictionary.

**Returns:** Dictionary mapping secret names to values

##### `get_as_env_dict() -> Dict[str, str]`
Get secrets as environment variable dictionary.

**Returns:** Dictionary with UPPER_SNAKE_CASE names

#### Properties

##### `is_unlocked: bool`
Check if currently unlocked.

##### `secret_count: int`
Get the number of loaded secrets.

### `Secret` (dataclass)

**Attributes:**
- `name` (str): Secret name
- `value` (str): Secret value
- `category` (str): Category (optional)

### Exceptions

- `SecretsManagerError`: Base exception
- `InvalidPasswordError`: Wrong password
- `SecretsFileNotFoundError`: Missing secrets file

## Command-Line Usage

The library includes a CLI tool:

```bash
# Run interactive demo
npp-secrets

# Or use Python
python -m npp_secrets.secrets_manager
```

Output:
```
Enter master password: ********
✓ Unlocked! Found 5 secrets.

Available secrets:
  • GitHub API Key [API Keys]
  • AWS Access Key [API Keys]
  • Database Password [Credentials]

Environment variable mapping:
  GITHUB_API_KEY=***
  AWS_ACCESS_KEY=***
  DATABASE_PASSWORD=***
```

## Use Cases

### 1. **CI/CD Scripts**
```python
from npp_secrets import SecretsManager

manager = SecretsManager()
manager.unlock(os.environ["NPP_MASTER_PASSWORD"])

# Deploy using secrets
deploy_api_key = manager.get_secret("Deploy Key")
deploy_to_server(api_key=deploy_api_key)
```

### 2. **Database Connections**
```python
from npp_secrets import SecretsManager
import psycopg2

manager = SecretsManager()
manager.unlock("master_pass")

db_password = manager.get_secret("Database Password")
conn = psycopg2.connect(
    host="localhost",
    user="admin",
    password=db_password
)
```

### 3. **API Testing**
```python
from npp_secrets import SecretsManager
import requests

manager = SecretsManager()
manager.unlock("master_pass")

api_key = manager.get_secret("Test API Key")
response = requests.get(
    "https://api.example.com/data",
    headers={"Authorization": f"Bearer {api_key}"}
)
```

### 4. **Configuration Files**
```python
from npp_secrets import SecretsManager
import json

manager = SecretsManager()
manager.unlock("master_pass")

config = {
    "api_key": manager.get_secret("API Key"),
    "secret": manager.get_secret("App Secret"),
    "token": manager.get_secret("Auth Token")
}

with open("config.json", "w") as f:
    json.dump(config, f)
```

## Security Considerations

### ✅ **What This Library Does**

- Encrypts secrets using Windows DPAPI (tied to your user account)
- Uses PBKDF2 with 10,000 iterations for key derivation
- Requires master password to decrypt
- Clears secrets from memory when locked

### ⚠️ **Important Notes**

- **Secrets are tied to your Windows user account** - Can't be decrypted on another machine or by another user
- **Master password is required** - Store it securely
- **Auto-lock after 60 minutes** - Plugin auto-locks, but Python library doesn't (call `lock()` when done)
- **No recovery** - If you forget the master password, secrets are lost
- **Windows only** - Uses Windows DPAPI

### 🔒 **Best Practices**

1. **Lock after use**: Always call `manager.lock()` when done
2. **Don't hardcode passwords**: Use environment variables or getpass
3. **Limit scope**: Only unlock when needed
4. **Use strong passwords**: For your master password
5. **Secure your scripts**: Don't commit scripts with passwords

## File Format

The library reads two binary files:

### `secrets_hash.dat`
```
[4 bytes: hash_size]
[hash_size bytes: SHA-256 hash of password]
```

### `secrets.dat`
```
[4 bytes: count]
For each secret:
  [4 bytes: name_size]
  [name_size bytes: encrypted name (salt + size + dpapi_data)]
  [4 bytes: value_size]
  [value_size bytes: encrypted value]
  [4 bytes: category_size]
  [category_size bytes: encrypted category]
```

### Encrypted Field Format
```
[16 bytes: salt]
[4 bytes: data_size]
[data_size bytes: DPAPI encrypted data]
```

## Development

### Running Tests

```bash
pytest tests/
```

### Type Checking

```bash
mypy npp_secrets/
```

### Code Formatting

```bash
black npp_secrets/
```

## Compatibility

| Component | Version |
|-----------|---------|
| Python | 3.7+ |
| Windows | 7+ |
| Notepad++ Plugin | v1.0+ |
| pywin32 | 300+ |

## License

This library is licensed under the **GNU General Public License v2.0 or later**, matching the Notepad++ plugin license.

See [LICENSE](../license.txt) for details.

## Contributing

Contributions welcome! Please:

1. Fork the repository
2. Create a feature branch
3. Add tests for new features
4. Submit a pull request

## Changelog

### 1.0.0 (2024)
- Initial release
- Read encrypted secrets from Notepad++ plugin
- Password verification
- Search and filtering
- Environment variable export
- CLI tool

## Support

For issues or questions:
- Open an issue on GitHub
- Check the [main plugin README](../README.md)

## Related Projects

- [Notepad++ Secrets Manager Plugin](../) - The C++ plugin for Notepad++

---

**Made with ❤️ for secure secret management in Notepad++**
