mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-09 15:58:48 +00:00
@@ -78,6 +78,7 @@ bash -c "$(curl -sSL https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/
|
|||||||
```powershell
|
```powershell
|
||||||
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; $scriptContent = (New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.ps1'); & ([scriptblock]::create($scriptContent))
|
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; $scriptContent = (New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.ps1'); & ([scriptblock]::create($scriptContent))
|
||||||
```
|
```
|
||||||
|
The Windows installer will attempt to install Git automatically if it is not already available.
|
||||||
*Install the beta branch:*
|
*Install the beta branch:*
|
||||||
```powershell
|
```powershell
|
||||||
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; $scriptContent = (New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.ps1'); & ([scriptblock]::create($scriptContent)) -Branch beta
|
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; $scriptContent = (New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.ps1'); & ([scriptblock]::create($scriptContent)) -Branch beta
|
||||||
|
@@ -32,7 +32,19 @@ function Write-Error {
|
|||||||
# 1. Check for prerequisites
|
# 1. Check for prerequisites
|
||||||
Write-Info "Installing SeedPass from branch: '$Branch'"
|
Write-Info "Installing SeedPass from branch: '$Branch'"
|
||||||
Write-Info "Checking for prerequisites..."
|
Write-Info "Checking for prerequisites..."
|
||||||
if (-not (Get-Command git -ErrorAction SilentlyContinue)) { Write-Error "Git is not installed. Please install it from https://git-scm.com/ and ensure it's in your PATH." }
|
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
|
||||||
|
Write-Warning "Git is not installed. Attempting to install..."
|
||||||
|
if (Get-Command winget -ErrorAction SilentlyContinue) {
|
||||||
|
try { winget install --id Git.Git -e --source winget -h } catch { Write-Error "Failed to install Git via winget. Error: $_" }
|
||||||
|
} elseif (Get-Command choco -ErrorAction SilentlyContinue) {
|
||||||
|
try { choco install git -y } catch { Write-Error "Failed to install Git via Chocolatey. Error: $_" }
|
||||||
|
} elseif (Get-Command scoop -ErrorAction SilentlyContinue) {
|
||||||
|
try { scoop install git } catch { Write-Error "Failed to install Git via Scoop. Error: $_" }
|
||||||
|
} else {
|
||||||
|
Write-Error "Git is not installed. Please install it from https://git-scm.com/ and ensure it's in your PATH."
|
||||||
|
}
|
||||||
|
if (-not (Get-Command git -ErrorAction SilentlyContinue)) { Write-Error "Git installation failed or git not found in PATH after installation." }
|
||||||
|
}
|
||||||
$pythonExe = Get-Command python -ErrorAction SilentlyContinue
|
$pythonExe = Get-Command python -ErrorAction SilentlyContinue
|
||||||
if (-not $pythonExe) { Write-Error "Python 3 is not installed or not in your PATH. Please install it from https://www.python.org/" }
|
if (-not $pythonExe) { Write-Error "Python 3 is not installed or not in your PATH. Please install it from https://www.python.org/" }
|
||||||
|
|
||||||
|
@@ -57,7 +57,21 @@ main() {
|
|||||||
|
|
||||||
# 2. Check for prerequisites
|
# 2. Check for prerequisites
|
||||||
print_info "Checking for prerequisites (git, python3, pip)..."
|
print_info "Checking for prerequisites (git, python3, pip)..."
|
||||||
if ! command -v git &> /dev/null; then print_error "Git is not installed. Please install it."; fi
|
if ! command -v git &> /dev/null; then
|
||||||
|
print_warning "Git is not installed. Attempting to install..."
|
||||||
|
if [ "$OS_NAME" = "Linux" ]; then
|
||||||
|
if command -v apt-get &> /dev/null; then sudo apt-get update && sudo apt-get install -y git;
|
||||||
|
elif command -v dnf &> /dev/null; then sudo dnf install -y git;
|
||||||
|
elif command -v pacman &> /dev/null; then sudo pacman -Syu --noconfirm git;
|
||||||
|
else print_error "Git is not installed and automatic installation is not supported on this system."; fi
|
||||||
|
elif [ "$OS_NAME" = "Darwin" ]; then
|
||||||
|
if command -v brew &> /dev/null; then brew install git;
|
||||||
|
else print_error "Git is not installed and Homebrew was not found. Please install Git manually."; fi
|
||||||
|
else
|
||||||
|
print_error "Git is not installed. Please install it."
|
||||||
|
fi
|
||||||
|
if ! command -v git &> /dev/null; then print_error "Git installation failed or git not found in PATH."; fi
|
||||||
|
fi
|
||||||
if ! command -v python3 &> /dev/null; then print_error "Python 3 is not installed. Please install it."; fi
|
if ! command -v python3 &> /dev/null; then print_error "Python 3 is not installed. Please install it."; fi
|
||||||
if ! python3 -m ensurepip --default-pip &> /dev/null && ! command -v pip3 &> /dev/null; then print_error "pip for Python 3 is not available. Please install it."; fi
|
if ! python3 -m ensurepip --default-pip &> /dev/null && ! command -v pip3 &> /dev/null; then print_error "pip for Python 3 is not available. Please install it."; fi
|
||||||
if ! python3 -c "import venv" &> /dev/null; then
|
if ! python3 -c "import venv" &> /dev/null; then
|
||||||
|
@@ -14,6 +14,7 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import getpass
|
import getpass
|
||||||
import os
|
import os
|
||||||
|
import hashlib
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import shutil
|
import shutil
|
||||||
import time
|
import time
|
||||||
@@ -2267,7 +2268,8 @@ class PasswordManager:
|
|||||||
|
|
||||||
# Schema version and checksum status
|
# Schema version and checksum status
|
||||||
stats["schema_version"] = data.get("schema_version")
|
stats["schema_version"] = data.get("schema_version")
|
||||||
current_checksum = json_checksum(data)
|
json_content = json.dumps(data, indent=4)
|
||||||
|
current_checksum = hashlib.sha256(json_content.encode("utf-8")).hexdigest()
|
||||||
chk_path = self.entry_manager.checksum_file
|
chk_path = self.entry_manager.checksum_file
|
||||||
if chk_path.exists():
|
if chk_path.exists():
|
||||||
stored = chk_path.read_text().strip()
|
stored = chk_path.read_text().strip()
|
||||||
|
@@ -4,6 +4,8 @@ from tempfile import TemporaryDirectory
|
|||||||
|
|
||||||
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
|
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
|
||||||
|
|
||||||
|
from nostr.coincurve_keys import Keys
|
||||||
|
|
||||||
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
||||||
|
|
||||||
from password_manager.entry_management import EntryManager
|
from password_manager.entry_management import EntryManager
|
||||||
@@ -36,3 +38,11 @@ def test_nostr_key_determinism():
|
|||||||
assert nsec1 == nsec2
|
assert nsec1 == nsec2
|
||||||
assert npub1.startswith("npub")
|
assert npub1.startswith("npub")
|
||||||
assert nsec1.startswith("nsec")
|
assert nsec1.startswith("nsec")
|
||||||
|
|
||||||
|
priv_hex = Keys.bech32_to_hex(nsec1)
|
||||||
|
derived = Keys(priv_k=priv_hex)
|
||||||
|
encoded_npub = Keys.hex_to_bech32(derived.public_key_hex(), "npub")
|
||||||
|
assert encoded_npub == npub1
|
||||||
|
|
||||||
|
data = enc_mgr.load_json_data(entry_mgr.index_file)
|
||||||
|
assert data["entries"][str(idx)]["label"] == "main"
|
||||||
|
@@ -25,3 +25,15 @@ def test_pgp_key_determinism():
|
|||||||
|
|
||||||
assert fp1 == fp2
|
assert fp1 == fp2
|
||||||
assert key1 == key2
|
assert key1 == key2
|
||||||
|
|
||||||
|
# parse returned armored key and verify fingerprint
|
||||||
|
from pgpy import PGPKey
|
||||||
|
|
||||||
|
parsed_key, _ = PGPKey.from_blob(key1)
|
||||||
|
assert parsed_key.fingerprint == fp1
|
||||||
|
|
||||||
|
# ensure the index file stores key_type and user_id
|
||||||
|
data = enc_mgr.load_json_data(entry_mgr.index_file)
|
||||||
|
entry = data["entries"][str(idx)]
|
||||||
|
assert entry["key_type"] == "ed25519"
|
||||||
|
assert entry["user_id"] == "Test"
|
||||||
|
@@ -3,6 +3,7 @@ from pathlib import Path
|
|||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
|
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
|
||||||
|
from mnemonic import Mnemonic
|
||||||
|
|
||||||
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
||||||
|
|
||||||
@@ -30,6 +31,9 @@ def test_seed_phrase_determinism():
|
|||||||
phrase24_a = entry_mgr.get_seed_phrase(idx_24, TEST_SEED)
|
phrase24_a = entry_mgr.get_seed_phrase(idx_24, TEST_SEED)
|
||||||
phrase24_b = entry_mgr.get_seed_phrase(idx_24, TEST_SEED)
|
phrase24_b = entry_mgr.get_seed_phrase(idx_24, TEST_SEED)
|
||||||
|
|
||||||
|
entry12 = entry_mgr.retrieve_entry(idx_12)
|
||||||
|
entry24 = entry_mgr.retrieve_entry(idx_24)
|
||||||
|
|
||||||
seed_bytes = Bip39SeedGenerator(TEST_SEED).Generate()
|
seed_bytes = Bip39SeedGenerator(TEST_SEED).Generate()
|
||||||
bip85 = BIP85(seed_bytes)
|
bip85 = BIP85(seed_bytes)
|
||||||
expected12 = derive_seed_phrase(bip85, idx_12, 12)
|
expected12 = derive_seed_phrase(bip85, idx_12, 12)
|
||||||
@@ -39,3 +43,7 @@ def test_seed_phrase_determinism():
|
|||||||
assert phrase24_a == phrase24_b == expected24
|
assert phrase24_a == phrase24_b == expected24
|
||||||
assert len(phrase12_a.split()) == 12
|
assert len(phrase12_a.split()) == 12
|
||||||
assert len(phrase24_a.split()) == 24
|
assert len(phrase24_a.split()) == 24
|
||||||
|
assert Mnemonic("english").check(phrase12_a)
|
||||||
|
assert Mnemonic("english").check(phrase24_a)
|
||||||
|
assert entry12.get("words") == 12
|
||||||
|
assert entry24.get("words") == 24
|
||||||
|
40
src/tests/test_ssh_entry_valid.py
Normal file
40
src/tests/test_ssh_entry_valid.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
|
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
|
||||||
|
|
||||||
|
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
||||||
|
|
||||||
|
from password_manager.entry_management import EntryManager
|
||||||
|
from password_manager.backup import BackupManager
|
||||||
|
from password_manager.vault import Vault
|
||||||
|
from password_manager.config_manager import ConfigManager
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
|
||||||
|
|
||||||
|
def test_ssh_private_key_corresponds_to_public():
|
||||||
|
with TemporaryDirectory() as tmpdir:
|
||||||
|
tmp_path = Path(tmpdir)
|
||||||
|
vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD)
|
||||||
|
cfg_mgr = ConfigManager(vault, tmp_path)
|
||||||
|
backup_mgr = BackupManager(tmp_path, cfg_mgr)
|
||||||
|
entry_mgr = EntryManager(vault, backup_mgr)
|
||||||
|
|
||||||
|
idx = entry_mgr.add_ssh_key(TEST_SEED)
|
||||||
|
priv_pem, pub_pem = entry_mgr.get_ssh_key_pair(idx, TEST_SEED)
|
||||||
|
|
||||||
|
priv_key = serialization.load_pem_private_key(
|
||||||
|
priv_pem.encode(),
|
||||||
|
password=None,
|
||||||
|
)
|
||||||
|
derived_pub_pem = (
|
||||||
|
priv_key.public_key()
|
||||||
|
.public_bytes(
|
||||||
|
serialization.Encoding.PEM,
|
||||||
|
serialization.PublicFormat.SubjectPublicKeyInfo,
|
||||||
|
)
|
||||||
|
.decode()
|
||||||
|
)
|
||||||
|
|
||||||
|
assert derived_pub_pem == pub_pem
|
Reference in New Issue
Block a user