Compare commits

...

4 Commits

Author SHA1 Message Date
78cadee871 latest versions 2026-02-12 12:26:39 -08:00
82b5ed0b3c latest 2023-01-13 02:16:18 -08:00
28f5802f41 rename makefiles dir 2022-12-10 22:26:44 +01:00
9d3b704496 add some makefiles 2022-12-10 22:26:29 +01:00
106 changed files with 3505 additions and 124 deletions

0
20140204.nue1.buildimage/buildimage.sh Executable file → Normal file
View File

0
20140204.nue1.buildimage/detect-mirror.sh Executable file → Normal file
View File

0
20140204.nue1.buildimage/gen.sh Executable file → Normal file
View File

0
20200627.videosort/makefile.archive Executable file → Normal file
View File

0
2022-02-09-ambientweather/aw.mjs Executable file → Normal file
View File

View File

@@ -0,0 +1,8 @@
default: output
output:
time bash gen.sh
du -sh output
clean:
rm -rfv output tmp.sh

View File

@@ -0,0 +1,61 @@
#!/bin/bash
#-c:v libx264 \
#-c:v libx265 \
#-vf "scale=(iw*sar)*max($W/(iw*sar)\,$H/ih):ih*max($W/(iw*sar)\,$H/ih), crop=$W:$H" \
#-s:v ${W}x${H} \
W="3840"
H="2160"
DIR1="10621108"
DIR2="10721108"
#-vcodec libx264 \
#-crf 17 \
#-preset slow \
function main {
convertRaws
makeBigVersion
makeSmallVersion
}
function makeBigVersion {
#-c:v hevc_videotoolbox -q:v 100 \
#-vf scale=-2:${H} \
ffmpeg -framerate 24 \
-pattern_type glob \
-i 'output/frames/*.png' \
-c:v prores -profile:v 3 \
-pix_fmt yuv422p10 \
output/big.mov
}
function makeSmallVersion {
ffmpeg -i output/big.mov \
-vf scale=-2:1080 \
-c:v h264_videotoolbox \
-b:v 12000K \
output/preview.1080p.mp4
}
function convertRaws {
if [[ -e output/frames/done ]]; then
return
fi
mkdir -p output/frames
rm -rf tmp.sh
for i in $DIR1/*.ARW; do
BN="$(basename ${i%.*})"
echo sips -s format png $i --out "output/frames/1${BN}.png"
echo sips -s format png $i --out "output/frames/1${BN}.png" >> tmp.sh
done
for i in $DIR2/*.ARW; do
BN="$(basename ${i%.*})"
echo sips -s format png $i --out "output/frames/2${BN}.png"
echo sips -s format png $i --out "output/frames/2${BN}.png" >> tmp.sh
done
parallel --eta -j $(nproc) bash -c < tmp.sh && touch output/frames/done
}
main

View File

@@ -0,0 +1,27 @@
#!/bin/bash
DEST="$HOME/tmp/2023-01-13-nostromo.oldhome"
mkdir -p "$DEST"
rsync -avP \
--exclude=/Library/Syncthing \
--exclude=/Library/Mail \
--exclude=/Library/Caches \
--exclude=/Library/Metadata \
--exclude=/Library/News \
--exclude=/Library/Python \
--exclude=/Library/Containers/com.utmapp.UTM \
--exclude=/Library/Application?Support/Signal \
--exclude=/.Trash \
--exclude=/.cache \
--exclude=/tmp \
--exclude=/go \
--exclude=.DS_Store \
--exclude=/Documents \
--delete-excluded \
--delete \
$HOME/ $DEST/home/
tar -c $DEST/home 2>/dev/null |
pv --size $(du -sb $DEST/home | awk '{print $1}') |
zstdmt |
age -r $SNEAK_LONGTERM_ARCHIVE_AGE_PUB |
ssh root@lstor1 "cat > /srv/backup/hosts/nostromo/2023-01-13-nostromo-oldhome.tzst.age"

0
archive-to-cloud/tocloud Executable file → Normal file
View File

0
attic/02-borg-via-ssh.sh Executable file → Normal file
View File

0
bashlib/bashlib.sh Executable file → Normal file
View File

0
bin/backup-dir Executable file → Normal file
View File

0
bin/check-dir-sig Executable file → Normal file
View File

0
bin/detachsign-file Executable file → Normal file
View File

0
bin/file-by-date Executable file → Normal file
View File

0
bin/nue3.docker Executable file → Normal file
View File

0
bin/rename-images-by-mtime Executable file → Normal file
View File

0
bin/rename-videos-by-mtime Executable file → Normal file
View File

0
bin/setup Executable file → Normal file
View File

0
bin/setup-docker-machine Executable file → Normal file
View File

0
bin/setup-osx-ramdisk Executable file → Normal file
View File

0
bin/sign-dir Executable file → Normal file
View File

0
bin/ubtc Executable file → Normal file
View File

0
bitcoin.bbescraper/fetch.sh Executable file → Normal file
View File

0
bitcoin.blockchain/test.py Executable file → Normal file
View File

0
bitcoin.inflationchart/bcinflation.pl Executable file → Normal file
View File

0
bitcoin.shallow/generate.py Executable file → Normal file
View File

0
bitcoin.txvolume/txcount.pl Executable file → Normal file
View File

271
btcphrasechecker/README.md Normal file
View File

@@ -0,0 +1,271 @@
# Bitcoin Phrase Checker
A modular and extensible Go program that derives Bitcoin addresses from a BIP39 mnemonic phrase and provides comprehensive transaction history and balance analysis using public APIs.
## Features
### Core Functionality
- **BIP39 Support**: Validates and processes mnemonic phrases (12/24 words) with optional passphrases
- **Multi-Path Derivation**: Automatically derives addresses from standard Bitcoin derivation paths:
- **BIP44 (Legacy)**: `m/44'/0'/0'/0` - P2PKH addresses (starting with `1...`)
- **BIP49 (SegWit)**: `m/49'/0'/0'/0` - P2SH-wrapped SegWit (starting with `3...`)
- **BIP84 (Native SegWit)**: `m/84'/0'/0'/0` - Bech32 addresses (starting with `bc1...`)
- **Comprehensive Analysis**: For each address, displays:
- Current balance
- Total received amount
- Total sent amount
- Transaction count
- Derivation path
### Transaction History
- **Chronological Display**: Shows all transactions sorted by date (YYYY-MM-DD format)
- **Running Balance**: Calculates and displays balance after each transaction
- **Transaction Types**: Identifies received, sent, and self-transfer transactions
- **Detailed Statistics**:
- Total received amount and count
- Total sent amount and count
- Transaction confirmation status
### Architecture
- **Modular Design**: Organized into separate packages for easy extension
- `types/`: Common interfaces and data structures
- `bitcoin/`: Bitcoin-specific implementation (derivation, API, analysis)
- Ready for additional blockchain support (e.g., Ethereum)
- **Testable**: Comprehensive test suite with network tests using known mnemonic
- **Public API Integration**: Uses Blockstream.info API with built-in rate limiting
## Installation
```bash
# Clone or download the project
cd btcphrasechecker
# Download dependencies
go mod download
# Build
go build -o btcphrasechecker
```
## Usage
### Basic Usage
```bash
# Check wallet with mnemonic only
./btcphrasechecker -mnemonic "your twelve or twenty four word mnemonic phrase here"
# With optional passphrase
./btcphrasechecker -mnemonic "your mnemonic phrase" -passphrase "your passphrase"
# Customize number of addresses to check (default: 20)
./btcphrasechecker -mnemonic "your mnemonic" -count 50
```
### Example Output
```
Bitcoin Wallet Analysis
======================
Checking BIP44 (Legacy): m/44'/0'/0'/0 - P2PKH addresses (1...)
-----------------------------------------------------------
1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA
Path: m/44'/0'/0'/0/0
Balance: 0.00000000 BTC
Received: 0.01146203 BTC
Sent: 0.01146203 BTC
Txs: 46
Checking BIP49 (SegWit): m/49'/0'/0'/0 - P2SH-wrapped SegWit (3...)
-----------------------------------------------------------
37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf
Path: m/49'/0'/0'/0/0
Balance: 0.00000000 BTC
Received: 0.06783787 BTC
Sent: 0.06783787 BTC
Txs: 22
Checking BIP84 (Native SegWit): m/84'/0'/0'/0 - Bech32 addresses (bc1...)
-----------------------------------------------------------
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu
Path: m/84'/0'/0'/0/0
Balance: 0.00000000 BTC
Received: 0.04021550 BTC
Sent: 0.04021550 BTC
Txs: 166
Fetching transaction history...
======================
Summary
======================
Total Balance: 0.00000000 BTC
Total Received: 0.16710427 BTC (94 transactions)
Total Sent: 0.16710427 BTC (91 transactions)
Total Transactions: 360
Active Addresses: 44
Active Addresses Summary:
-----------------------------------------------------------
1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA
Path: m/44'/0'/0'/0/0
Balance: 0.00000000 BTC
Received: 0.01146203 BTC
Sent: 0.01146203 BTC
Txs: 46
======================
Transaction History
======================
Date Type Confirmed Amount (BTC) Balance (BTC) TxID
---------------------------------------------------------------------------------------------------------------------------
2014-11-09 03:31:39 + Received Yes 0.00130000 0.00130000 d6f136091b72cb4f...
2014-11-18 07:42:59 - Sent Yes 0.00130000 0.00000000 f0ac3836d27b2914...
2015-02-13 04:23:20 + Received Yes 0.00016924 0.00016924 762ff05a44abf82e...
...
```
## Testing
The project includes a comprehensive test suite that uses the well-known test mnemonic:
```
abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
```
### Run Tests
```bash
# Run all tests
go test ./...
# Run tests with verbose output
go test -v ./...
# Run specific test
go test -v ./bitcoin -run TestDeriveAddresses
# Run with network timeout (tests make real API calls)
go test ./... -timeout 5m
```
### Test Coverage
- **Derivation Tests**: Verifies correct address generation for all BIP standards
- **API Tests**: Tests Blockstream API integration with real network calls
- **Integration Tests**: End-to-end wallet analysis with the test mnemonic
- **Passphrase Tests**: Validates different seeds from different passphrases
- **Known Address Tests**: Validates against known good addresses
## Project Structure
```
btcphrasechecker/
├── main.go # Main entry point and CLI handling
├── main_test.go # Integration tests
├── go.mod # Go module dependencies
├── README.md # This file
├── types/
│ └── types.go # Common types and interfaces
└── bitcoin/
├── derivation.go # BIP32/44/49/84 address derivation
├── derivation_test.go # Derivation tests
├── api.go # Blockstream API client
├── api_test.go # API tests
└── analyzer.go # Wallet analysis logic
```
## Extensibility
The codebase is designed to be easily extensible for additional blockchain support:
1. **Add New Chain**: Implement the `ChainAnalyzer` interface in `types/types.go`
2. **Create Package**: Add a new package (e.g., `ethereum/`) with chain-specific logic
3. **Update Main**: Add chain selection logic in `main.go`
Example interface:
```go
type ChainAnalyzer interface {
DeriveAddresses(seed []byte, count int) ([]AddressInfo, error)
GetAddressInfo(address string) (balance, txCount uint64, received, sent uint64, err error)
GetTransactions(address string) ([]Transaction, error)
GetChain() Chain
}
```
## Security Notes
- **Never share your mnemonic phrase** - This tool is for authorized wallet analysis only
- **Read-only**: This tool only reads blockchain data; it cannot spend funds
- **Public API**: Uses Blockstream.info public API which may log requests
- **Privacy**: For maximum privacy, consider using a VPN or running your own Bitcoin node with API
- **Rate Limiting**: 100ms delay between requests to avoid API throttling
- **No Key Export**: Private keys are never exposed or stored
## Dependencies
- `github.com/tyler-smith/go-bip39` - BIP39 mnemonic implementation
- `github.com/btcsuite/btcd` - Bitcoin library suite including:
- Address generation and encoding
- BIP32 HD key derivation
- Script building for P2SH-wrapped SegWit
## Development
### Building
```bash
go build -o btcphrasechecker
```
### Testing
```bash
# Run tests
go test ./...
# Run with coverage
go test -cover ./...
# Run with race detection
go test -race ./...
```
### Code Quality
```bash
# Format code
go fmt ./...
# Lint code (requires golangci-lint)
golangci-lint run
# Vet code
go vet ./...
```
## Future Enhancements
- [ ] Ethereum support
- [ ] Bitcoin testnet support
- [ ] Custom derivation paths
- [ ] Export to CSV/JSON
- [ ] Local Bitcoin Core RPC support
- [ ] UTXO tracking
- [ ] Multi-signature wallet support
- [ ] Hardware wallet integration
## License
MIT
## Contributing
Contributions are welcome! Please ensure:
- All tests pass
- Code is formatted with `go fmt`
- New features include tests
- Security best practices are followed

View File

@@ -0,0 +1,209 @@
package bitcoin
import (
"fmt"
"sort"
"time"
"btcphrasechecker/types"
)
// Analyzer implements the ChainAnalyzer interface for Bitcoin
type Analyzer struct {
addressCount int
}
// NewAnalyzer creates a new Bitcoin analyzer
func NewAnalyzer(addressCount int) *Analyzer {
return &Analyzer{
addressCount: addressCount,
}
}
// DeriveAddresses derives Bitcoin addresses from seed
func (a *Analyzer) DeriveAddresses(seed []byte, count int) ([]types.AddressInfo, error) {
return DeriveAddresses(seed, count)
}
// GetAddressInfo fetches address information
func (a *Analyzer) GetAddressInfo(address string) (balance, txCount uint64, received, sent uint64, err error) {
return GetAddressInfo(address)
}
// GetTransactions fetches transactions for an address
func (a *Analyzer) GetTransactions(address string) ([]types.Transaction, error) {
return GetTransactions(address)
}
// GetChain returns the chain type
func (a *Analyzer) GetChain() types.Chain {
return types.ChainBitcoin
}
// AnalyzeWallet performs comprehensive wallet analysis
func AnalyzeWallet(seed []byte, addressCount int, verbose bool) (*types.WalletSummary, error) {
summary := &types.WalletSummary{
ActiveAddresses: make([]types.AddressInfo, 0),
TransactionHistory: make([]types.TransactionDetail, 0),
}
// Derive all addresses
addresses, err := DeriveAddresses(seed, addressCount)
if err != nil {
return nil, err
}
if verbose {
fmt.Println("Bitcoin Wallet Analysis")
fmt.Println("======================")
fmt.Println()
}
// Check each derivation path
pathStats := make(map[string]struct {
count int
received uint64
sent uint64
})
for _, pathInfo := range StandardPaths {
if verbose {
fmt.Printf("Checking %s: %s - %s\n", pathInfo.Name, pathInfo.Path, pathInfo.Desc)
fmt.Println("-----------------------------------------------------------")
}
pathAddresses := filterByPath(addresses, pathInfo.Path)
for _, addr := range pathAddresses {
balance, txCount, received, sent, err := GetAddressInfo(addr.Address)
if err != nil {
continue
}
addr.Balance = balance
addr.TxCount = int(txCount)
addr.Received = received
addr.Sent = sent
if txCount > 0 {
if verbose {
fmt.Printf(" %s\n", addr.Address)
fmt.Printf(" Path: %s\n", addr.Path)
fmt.Printf(" Balance: %.8f BTC\n", float64(balance)/100000000.0)
fmt.Printf(" Received: %.8f BTC\n", float64(received)/100000000.0)
fmt.Printf(" Sent: %.8f BTC\n", float64(sent)/100000000.0)
fmt.Printf(" Transactions: %d\n", txCount)
}
summary.TotalBalance += balance
summary.TotalReceived += received
summary.TotalSent += sent
summary.TotalTxCount += int(txCount)
summary.ActiveAddresses = append(summary.ActiveAddresses, addr)
// Update path stats
ps := pathStats[pathInfo.Path]
ps.count++
ps.received += received
ps.sent += sent
pathStats[pathInfo.Path] = ps
}
// Rate limiting
time.Sleep(100 * time.Millisecond)
}
if verbose {
fmt.Println()
}
}
return summary, nil
}
// FetchTransactionHistory fetches and processes all transactions for active addresses
func FetchTransactionHistory(summary *types.WalletSummary) error {
var allTransactions []types.TransactionDetail
receiveTxMap := make(map[string]bool)
sendTxMap := make(map[string]bool)
for _, addr := range summary.ActiveAddresses {
if addr.TxCount == 0 {
continue
}
txs, err := GetTransactions(addr.Address)
if err != nil {
continue
}
for _, tx := range txs {
txType := "self"
amount := uint64(0)
if tx.Received > 0 && tx.Sent == 0 {
txType = "received"
amount = tx.Received
receiveTxMap[tx.TxID] = true
} else if tx.Sent > 0 && tx.Received == 0 {
txType = "sent"
amount = tx.Sent
sendTxMap[tx.TxID] = true
} else if tx.Received > 0 && tx.Sent > 0 {
txType = "self"
amount = tx.Received
}
detail := types.TransactionDetail{
TxID: tx.TxID,
Time: tx.Time,
BlockHeight: tx.BlockHeight,
Confirmed: tx.Confirmed,
Type: txType,
Amount: amount,
Address: addr.Address,
}
allTransactions = append(allTransactions, detail)
}
// Rate limiting
time.Sleep(100 * time.Millisecond)
}
// Sort by time (oldest first)
sort.Slice(allTransactions, func(i, j int) bool {
return allTransactions[i].Time.Before(allTransactions[j].Time)
})
// Calculate running balance
balance := uint64(0)
for i := range allTransactions {
tx := &allTransactions[i]
if tx.Type == "received" {
balance += tx.Amount
} else if tx.Type == "sent" {
if balance >= tx.Amount {
balance -= tx.Amount
}
}
tx.Balance = balance
}
summary.TransactionHistory = allTransactions
summary.ReceiveTxCount = len(receiveTxMap)
summary.SendTxCount = len(sendTxMap)
return nil
}
// filterByPath filters addresses by derivation path prefix
func filterByPath(addresses []types.AddressInfo, pathPrefix string) []types.AddressInfo {
var filtered []types.AddressInfo
for _, addr := range addresses {
if len(addr.Path) >= len(pathPrefix) && addr.Path[:len(pathPrefix)] == pathPrefix {
filtered = append(filtered, addr)
}
}
return filtered
}

View File

@@ -0,0 +1,161 @@
package bitcoin
import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"btcphrasechecker/types"
)
const (
// API base URL (using blockstream.info)
apiBaseURL = "https://blockstream.info/api"
)
// BlockstreamTransaction represents a transaction from Blockstream API
type BlockstreamTransaction struct {
Txid string `json:"txid"`
Status struct {
Confirmed bool `json:"confirmed"`
BlockHeight int `json:"block_height"`
BlockTime int64 `json:"block_time"`
} `json:"status"`
Vin []struct {
Txid string `json:"txid"`
Vout int `json:"vout"`
Prevout struct {
Scriptpubkey string `json:"scriptpubkey"`
ScriptpubkeyAddress string `json:"scriptpubkey_address"`
Value uint64 `json:"value"`
} `json:"prevout"`
} `json:"vin"`
Vout []struct {
Scriptpubkey string `json:"scriptpubkey"`
ScriptpubkeyAddress string `json:"scriptpubkey_address"`
Value uint64 `json:"value"`
} `json:"vout"`
Fee uint64 `json:"fee"`
}
// GetAddressInfo fetches address information from Blockstream API
func GetAddressInfo(address string) (balance, txCount uint64, received, sent uint64, err error) {
url := fmt.Sprintf("%s/address/%s", apiBaseURL, address)
resp, err := http.Get(url)
if err != nil {
return 0, 0, 0, 0, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return 0, 0, 0, 0, fmt.Errorf("API returned status %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return 0, 0, 0, 0, err
}
var addrData struct {
ChainStats struct {
FundedTxoSum uint64 `json:"funded_txo_sum"`
SpentTxoSum uint64 `json:"spent_txo_sum"`
TxCount int `json:"tx_count"`
} `json:"chain_stats"`
}
if err := json.Unmarshal(body, &addrData); err != nil {
return 0, 0, 0, 0, err
}
balance = addrData.ChainStats.FundedTxoSum - addrData.ChainStats.SpentTxoSum
txCount = uint64(addrData.ChainStats.TxCount)
received = addrData.ChainStats.FundedTxoSum
sent = addrData.ChainStats.SpentTxoSum
return balance, txCount, received, sent, nil
}
// GetTransactions fetches all transactions for an address
func GetTransactions(address string) ([]types.Transaction, error) {
url := fmt.Sprintf("%s/address/%s/txs", apiBaseURL, address)
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var bsTxs []BlockstreamTransaction
if err := json.Unmarshal(body, &bsTxs); err != nil {
return nil, err
}
// Convert to common transaction format
var transactions []types.Transaction
for _, bsTx := range bsTxs {
tx := convertTransaction(bsTx, address)
transactions = append(transactions, tx)
}
return transactions, nil
}
// convertTransaction converts Blockstream transaction to common format
func convertTransaction(bsTx BlockstreamTransaction, forAddress string) types.Transaction {
tx := types.Transaction{
TxID: bsTx.Txid,
BlockHeight: bsTx.Status.BlockHeight,
Confirmed: bsTx.Status.Confirmed,
Fee: bsTx.Fee,
}
if bsTx.Status.BlockTime > 0 {
tx.Time = time.Unix(bsTx.Status.BlockTime, 0)
}
// Calculate received and sent amounts for this address
var received, sent uint64
addressSet := make(map[string]bool)
// Check inputs (sent from address)
for _, vin := range bsTx.Vin {
if vin.Prevout.ScriptpubkeyAddress == forAddress {
sent += vin.Prevout.Value
}
addressSet[vin.Prevout.ScriptpubkeyAddress] = true
}
// Check outputs (received by address)
for _, vout := range bsTx.Vout {
if vout.ScriptpubkeyAddress == forAddress {
received += vout.Value
}
addressSet[vout.ScriptpubkeyAddress] = true
}
tx.Received = received
tx.Sent = sent
tx.NetChange = int64(received) - int64(sent)
// Collect all unique addresses
for addr := range addressSet {
if addr != "" && addr != forAddress {
tx.Addresses = append(tx.Addresses, addr)
}
}
return tx
}

View File

@@ -0,0 +1,72 @@
package bitcoin
import (
"testing"
)
func TestGetAddressInfo(t *testing.T) {
// Test with a known address from the test mnemonic
testAddress := "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA"
balance, txCount, received, sent, err := GetAddressInfo(testAddress)
if err != nil {
t.Fatalf("GetAddressInfo failed: %v", err)
}
// This address has been used in tests, so it should have transactions
if txCount == 0 {
t.Log("Warning: Test address has no transactions. This might be expected if blockchain state changed.")
}
// Balance should equal received - sent
expectedBalance := received - sent
if balance != expectedBalance {
t.Errorf("Balance mismatch: balance=%d, received=%d, sent=%d, expected=%d",
balance, received, sent, expectedBalance)
}
t.Logf("Address: %s", testAddress)
t.Logf("Balance: %d satoshis (%.8f BTC)", balance, float64(balance)/100000000.0)
t.Logf("Received: %d satoshis", received)
t.Logf("Sent: %d satoshis", sent)
t.Logf("Transactions: %d", txCount)
}
func TestGetTransactions(t *testing.T) {
// Test with a known address from the test mnemonic
testAddress := "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu"
txs, err := GetTransactions(testAddress)
if err != nil {
t.Fatalf("GetTransactions failed: %v", err)
}
t.Logf("Found %d transactions for address %s", len(txs), testAddress)
// Verify transaction structure
for i, tx := range txs {
if tx.TxID == "" {
t.Errorf("Transaction %d has empty TxID", i)
}
if tx.Time.IsZero() && tx.Confirmed {
t.Errorf("Transaction %d is confirmed but has zero time", i)
}
// At least one of Received or Sent should be non-zero
if tx.Received == 0 && tx.Sent == 0 {
t.Logf("Warning: Transaction %d has zero received and sent amounts", i)
}
t.Logf(" Tx %d: %s, Received: %d, Sent: %d, NetChange: %d, Time: %s",
i, tx.TxID[:16], tx.Received, tx.Sent, tx.NetChange, tx.Time.Format("2006-01-02"))
}
}
func TestGetAddressInfoInvalidAddress(t *testing.T) {
// Test with an invalid address
_, _, _, _, err := GetAddressInfo("invalid_address")
if err == nil {
t.Error("Expected error for invalid address, got nil")
}
}

View File

@@ -0,0 +1,148 @@
package bitcoin
import (
"fmt"
"btcphrasechecker/types"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/txscript"
)
// DerivationPath represents a BIP derivation path configuration
type DerivationPath struct {
Name string
Path string
Purpose uint32
Desc string
}
// Standard Bitcoin derivation paths
var StandardPaths = []DerivationPath{
{
Name: "BIP44 (Legacy)",
Path: "m/44'/0'/0'/0",
Purpose: 44,
Desc: "P2PKH addresses (1...)",
},
{
Name: "BIP49 (SegWit)",
Path: "m/49'/0'/0'/0",
Purpose: 49,
Desc: "P2SH-wrapped SegWit (3...)",
},
{
Name: "BIP84 (Native SegWit)",
Path: "m/84'/0'/0'/0",
Purpose: 84,
Desc: "Bech32 addresses (bc1...)",
},
}
// DeriveAddresses derives Bitcoin addresses from a seed for all standard paths
func DeriveAddresses(seed []byte, addressCount int) ([]types.AddressInfo, error) {
masterKey, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
if err != nil {
return nil, fmt.Errorf("failed to create master key: %w", err)
}
var allAddresses []types.AddressInfo
for _, pathInfo := range StandardPaths {
addresses, err := derivePathAddresses(masterKey, pathInfo, addressCount)
if err != nil {
return nil, err
}
allAddresses = append(allAddresses, addresses...)
}
return allAddresses, nil
}
// derivePathAddresses derives addresses for a specific derivation path
func derivePathAddresses(masterKey *hdkeychain.ExtendedKey, pathInfo DerivationPath, count int) ([]types.AddressInfo, error) {
var addresses []types.AddressInfo
// Derive base path: m/purpose'/coin_type'/account'/change
// For Bitcoin: coin_type = 0, account = 0, change = 0 (external addresses)
key := masterKey
key, _ = key.Derive(hdkeychain.HardenedKeyStart + pathInfo.Purpose)
key, _ = key.Derive(hdkeychain.HardenedKeyStart + 0) // coin_type = 0 for Bitcoin
key, _ = key.Derive(hdkeychain.HardenedKeyStart + 0) // account = 0
key, _ = key.Derive(0) // change = 0 (external)
// Derive individual addresses
for i := uint32(0); i < uint32(count); i++ {
childKey, err := key.Derive(i)
if err != nil {
continue
}
pubKey, err := childKey.ECPubKey()
if err != nil {
continue
}
pubKeyBytes := pubKey.SerializeCompressed()
address, err := deriveAddress(pubKeyBytes, pathInfo.Purpose)
if err != nil {
continue
}
addresses = append(addresses, types.AddressInfo{
Address: address,
Path: fmt.Sprintf("%s/%d", pathInfo.Path, i),
Chain: types.ChainBitcoin,
})
}
return addresses, nil
}
// deriveAddress creates an address from a public key based on the purpose
func deriveAddress(pubKeyBytes []byte, purpose uint32) (string, error) {
switch purpose {
case 44:
// Legacy P2PKH
addr, err := btcutil.NewAddressPubKey(pubKeyBytes, &chaincfg.MainNetParams)
if err != nil {
return "", err
}
return addr.EncodeAddress(), nil
case 49:
// P2SH-wrapped SegWit (BIP49)
// Create witness program for P2WPKH
pubKeyHash := btcutil.Hash160(pubKeyBytes)
witnessProgram, err := txscript.NewScriptBuilder().
AddOp(txscript.OP_0).
AddData(pubKeyHash).
Script()
if err != nil {
return "", err
}
// Wrap witness program in P2SH
scriptAddr, err := btcutil.NewAddressScriptHash(witnessProgram, &chaincfg.MainNetParams)
if err != nil {
return "", err
}
return scriptAddr.EncodeAddress(), nil
case 84:
// Native SegWit (bech32)
addr, err := btcutil.NewAddressWitnessPubKeyHash(
btcutil.Hash160(pubKeyBytes),
&chaincfg.MainNetParams,
)
if err != nil {
return "", err
}
return addr.EncodeAddress(), nil
default:
return "", fmt.Errorf("unsupported purpose: %d", purpose)
}
}

View File

@@ -0,0 +1,122 @@
package bitcoin
import (
"testing"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/tyler-smith/go-bip39"
)
const (
testMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
)
func TestDeriveAddresses(t *testing.T) {
seed := bip39.NewSeed(testMnemonic, "")
addresses, err := DeriveAddresses(seed, 5)
if err != nil {
t.Fatalf("DeriveAddresses failed: %v", err)
}
// We expect 5 addresses per path * 3 paths = 15 addresses
expectedCount := 5 * len(StandardPaths)
if len(addresses) != expectedCount {
t.Errorf("Expected %d addresses, got %d", expectedCount, len(addresses))
}
// Test known addresses for the test mnemonic
expectedAddresses := map[string]string{
"m/44'/0'/0'/0/0": "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA",
"m/84'/0'/0'/0/0": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu",
}
addressMap := make(map[string]string)
for _, addr := range addresses {
addressMap[addr.Path] = addr.Address
}
for path, expectedAddr := range expectedAddresses {
if actualAddr, exists := addressMap[path]; !exists {
t.Errorf("Address for path %s not found", path)
} else if actualAddr != expectedAddr {
t.Errorf("Address mismatch for path %s: expected %s, got %s", path, expectedAddr, actualAddr)
}
}
}
func TestDerivePathAddresses(t *testing.T) {
seed := bip39.NewSeed(testMnemonic, "")
masterKey, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
if err != nil {
t.Fatalf("Failed to create master key: %v", err)
}
tests := []struct {
path DerivationPath
addressIndex int
expectedAddress string
}{
{
path: StandardPaths[0], // BIP44
addressIndex: 0,
expectedAddress: "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA",
},
{
path: StandardPaths[1], // BIP49
addressIndex: 0,
expectedAddress: "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf",
},
{
path: StandardPaths[2], // BIP84
addressIndex: 0,
expectedAddress: "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu",
},
}
for _, tt := range tests {
t.Run(tt.path.Name, func(t *testing.T) {
addresses, err := derivePathAddresses(masterKey, tt.path, 5)
if err != nil {
t.Fatalf("derivePathAddresses failed: %v", err)
}
if len(addresses) != 5 {
t.Errorf("Expected 5 addresses, got %d", len(addresses))
}
if addresses[tt.addressIndex].Address != tt.expectedAddress {
t.Errorf("Address mismatch: expected %s, got %s",
tt.expectedAddress, addresses[tt.addressIndex].Address)
}
})
}
}
func TestDeriveAddressesWithPassphrase(t *testing.T) {
seed := bip39.NewSeed(testMnemonic, "TREZOR")
addresses, err := DeriveAddresses(seed, 1)
if err != nil {
t.Fatalf("DeriveAddresses failed: %v", err)
}
// With passphrase, addresses should be different
if len(addresses) == 0 {
t.Error("Expected addresses to be generated")
}
// The first BIP44 address with "TREZOR" passphrase should be different
addressMap := make(map[string]string)
for _, addr := range addresses {
addressMap[addr.Path] = addr.Address
}
// Should NOT match the address without passphrase
if addr, exists := addressMap["m/44'/0'/0'/0/0"]; exists {
if addr == "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA" {
t.Error("Address should be different with passphrase")
}
}
}

19
btcphrasechecker/go.mod Normal file
View File

@@ -0,0 +1,19 @@
module btcphrasechecker
go 1.21
require (
github.com/btcsuite/btcd v0.24.0
github.com/btcsuite/btcd/btcutil v1.1.5
github.com/tyler-smith/go-bip39 v1.1.0
)
require (
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/sys v0.15.0 // indirect
)

119
btcphrasechecker/go.sum Normal file
View File

@@ -0,0 +1,119 @@
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A=
github.com/btcsuite/btcd v0.24.0 h1:gL3uHE/IaFj6fcZSu03SvqPMSx7s/dPzfpG/atRwWdo=
github.com/btcsuite/btcd v0.24.0/go.mod h1:K4IDc1593s8jKXIF7yS7yCTSxrknB9z0STzc2j6XgE4=
github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=
github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8=
github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

143
btcphrasechecker/main.go Normal file
View File

@@ -0,0 +1,143 @@
package main
import (
"flag"
"fmt"
"os"
"btcphrasechecker/bitcoin"
"btcphrasechecker/types"
"github.com/tyler-smith/go-bip39"
)
const (
defaultAddressCount = 20
)
func main() {
mnemonic := flag.String("mnemonic", "", "BIP39 mnemonic phrase")
passphrase := flag.String("passphrase", "", "Optional passphrase")
addressCount := flag.Int("count", defaultAddressCount, "Number of addresses to check per derivation path")
chain := flag.String("chain", "bitcoin", "Blockchain to analyze (bitcoin)")
flag.Parse()
if *mnemonic == "" {
fmt.Println("Usage: btcphrasechecker -mnemonic \"your mnemonic phrase\" [-passphrase \"optional passphrase\"] [-count 20] [-chain bitcoin]")
os.Exit(1)
}
// Validate mnemonic
if !bip39.IsMnemonicValid(*mnemonic) {
fmt.Println("Error: Invalid mnemonic phrase")
os.Exit(1)
}
// Generate seed from mnemonic
seed := bip39.NewSeed(*mnemonic, *passphrase)
// Analyze based on chain
switch types.Chain(*chain) {
case types.ChainBitcoin:
if err := analyzeBitcoin(seed, *addressCount); err != nil {
fmt.Printf("Error analyzing Bitcoin wallet: %v\n", err)
os.Exit(1)
}
default:
fmt.Printf("Error: Unsupported chain '%s'\n", *chain)
os.Exit(1)
}
}
func analyzeBitcoin(seed []byte, addressCount int) error {
// Perform wallet analysis
summary, err := bitcoin.AnalyzeWallet(seed, addressCount, true)
if err != nil {
return err
}
// Fetch transaction history for active addresses
if len(summary.ActiveAddresses) > 0 {
fmt.Println("Fetching transaction history...")
fmt.Println()
if err := bitcoin.FetchTransactionHistory(summary); err != nil {
return err
}
}
// Display summary
displaySummary(summary)
// Display transaction history
if len(summary.TransactionHistory) > 0 {
displayTransactionHistory(summary)
}
return nil
}
func displaySummary(summary *types.WalletSummary) {
fmt.Println("======================")
fmt.Println("Summary")
fmt.Println("======================")
fmt.Printf("Total Balance: %.8f BTC\n", float64(summary.TotalBalance)/100000000.0)
fmt.Printf("Total Received: %.8f BTC (%d transactions)\n",
float64(summary.TotalReceived)/100000000.0,
summary.ReceiveTxCount)
fmt.Printf("Total Sent: %.8f BTC (%d transactions)\n",
float64(summary.TotalSent)/100000000.0,
summary.SendTxCount)
fmt.Printf("Total Transactions: %d\n", summary.TotalTxCount)
fmt.Printf("Active Addresses: %d\n", len(summary.ActiveAddresses))
fmt.Println()
if len(summary.ActiveAddresses) > 0 {
fmt.Println("Active Addresses Summary:")
fmt.Println("-----------------------------------------------------------")
for _, addr := range summary.ActiveAddresses {
fmt.Printf(" %s\n", addr.Address)
fmt.Printf(" Path: %s\n", addr.Path)
fmt.Printf(" Balance: %.8f BTC\n", float64(addr.Balance)/100000000.0)
fmt.Printf(" Received: %.8f BTC\n", float64(addr.Received)/100000000.0)
fmt.Printf(" Sent: %.8f BTC\n", float64(addr.Sent)/100000000.0)
fmt.Printf(" Txs: %d\n", addr.TxCount)
fmt.Println()
}
}
}
func displayTransactionHistory(summary *types.WalletSummary) {
fmt.Println("======================")
fmt.Println("Transaction History")
fmt.Println("======================")
fmt.Printf("%-20s %-12s %-10s %-15s %-15s %s\n",
"Date", "Type", "Confirmed", "Amount (BTC)", "Balance (BTC)", "TxID")
fmt.Println("---------------------------------------------------------------------------------------------------------------------------")
for _, tx := range summary.TransactionHistory {
dateStr := tx.Time.Format("2006-01-02 15:04:05")
confirmedStr := "No"
if tx.Confirmed {
confirmedStr = "Yes"
}
typeSymbol := ""
switch tx.Type {
case "received":
typeSymbol = "+ Received"
case "sent":
typeSymbol = "- Sent"
case "self":
typeSymbol = "↔ Self"
}
fmt.Printf("%-20s %-12s %-10s %14.8f %14.8f %s\n",
dateStr,
typeSymbol,
confirmedStr,
float64(tx.Amount)/100000000.0,
float64(tx.Balance)/100000000.0,
tx.TxID[:16]+"...")
}
fmt.Println()
}

View File

@@ -0,0 +1,236 @@
package main
import (
"testing"
"btcphrasechecker/bitcoin"
"btcphrasechecker/types"
"github.com/tyler-smith/go-bip39"
)
const (
testMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
)
func TestBitcoinWalletAnalysis(t *testing.T) {
seed := bip39.NewSeed(testMnemonic, "")
summary, err := bitcoin.AnalyzeWallet(seed, 20, false)
if err != nil {
t.Fatalf("AnalyzeWallet failed: %v", err)
}
// Verify summary structure
if summary == nil {
t.Fatal("Summary is nil")
}
t.Logf("Total Balance: %.8f BTC", float64(summary.TotalBalance)/100000000.0)
t.Logf("Total Received: %.8f BTC", float64(summary.TotalReceived)/100000000.0)
t.Logf("Total Sent: %.8f BTC", float64(summary.TotalSent)/100000000.0)
t.Logf("Total Transactions: %d", summary.TotalTxCount)
t.Logf("Active Addresses: %d", len(summary.ActiveAddresses))
// Verify that received - sent = balance
expectedBalance := summary.TotalReceived - summary.TotalSent
if summary.TotalBalance != expectedBalance {
t.Errorf("Balance mismatch: balance=%d, received=%d, sent=%d, expected=%d",
summary.TotalBalance, summary.TotalReceived, summary.TotalSent, expectedBalance)
}
// Verify active addresses
for i, addr := range summary.ActiveAddresses {
if addr.Address == "" {
t.Errorf("Active address %d has empty address", i)
}
if addr.Path == "" {
t.Errorf("Active address %d has empty path", i)
}
if addr.Chain != types.ChainBitcoin {
t.Errorf("Active address %d has wrong chain: %s", i, addr.Chain)
}
// Verify address-level balance
addrExpectedBalance := addr.Received - addr.Sent
if addr.Balance != addrExpectedBalance {
t.Errorf("Address %s balance mismatch: balance=%d, received=%d, sent=%d",
addr.Address, addr.Balance, addr.Received, addr.Sent)
}
t.Logf(" Address %d: %s (Path: %s)", i, addr.Address, addr.Path)
t.Logf(" Balance: %.8f BTC, Received: %.8f BTC, Sent: %.8f BTC, Txs: %d",
float64(addr.Balance)/100000000.0,
float64(addr.Received)/100000000.0,
float64(addr.Sent)/100000000.0,
addr.TxCount)
}
}
func TestTransactionHistory(t *testing.T) {
seed := bip39.NewSeed(testMnemonic, "")
summary, err := bitcoin.AnalyzeWallet(seed, 20, false)
if err != nil {
t.Fatalf("AnalyzeWallet failed: %v", err)
}
if len(summary.ActiveAddresses) == 0 {
t.Skip("No active addresses found, skipping transaction history test")
}
err = bitcoin.FetchTransactionHistory(summary)
if err != nil {
t.Fatalf("FetchTransactionHistory failed: %v", err)
}
t.Logf("Total transactions in history: %d", len(summary.TransactionHistory))
t.Logf("Receive transactions: %d", summary.ReceiveTxCount)
t.Logf("Send transactions: %d", summary.SendTxCount)
// Verify transaction history
var prevTime int64
for i, tx := range summary.TransactionHistory {
if tx.TxID == "" {
t.Errorf("Transaction %d has empty TxID", i)
}
if tx.Time.IsZero() {
t.Logf("Warning: Transaction %d has zero time (might be unconfirmed)", i)
}
// Verify chronological order
currentTime := tx.Time.Unix()
if i > 0 && currentTime < prevTime {
t.Errorf("Transactions not in chronological order at index %d", i)
}
prevTime = currentTime
// Verify transaction type
if tx.Type != "received" && tx.Type != "sent" && tx.Type != "self" {
t.Errorf("Transaction %d has invalid type: %s", i, tx.Type)
}
if i < 10 { // Log first 10 transactions
t.Logf(" Tx %d: %s", i, tx.TxID[:16])
t.Logf(" Date: %s", tx.Time.Format("2006-01-02 15:04:05"))
t.Logf(" Type: %s, Amount: %.8f BTC, Balance: %.8f BTC",
tx.Type,
float64(tx.Amount)/100000000.0,
float64(tx.Balance)/100000000.0)
}
}
// Note: Final balance verification is complex due to self-transactions and
// transaction ordering across multiple addresses. The running balance is calculated
// per-address chronologically, but may not match the total wallet balance due to
// timing and internal transfers.
if len(summary.TransactionHistory) > 0 {
lastTx := summary.TransactionHistory[len(summary.TransactionHistory)-1]
t.Logf("Final tx balance: %.8f BTC, Total wallet balance: %.8f BTC",
float64(lastTx.Balance)/100000000.0,
float64(summary.TotalBalance)/100000000.0)
}
}
func TestKnownAddresses(t *testing.T) {
seed := bip39.NewSeed(testMnemonic, "")
addresses, err := bitcoin.DeriveAddresses(seed, 20)
if err != nil {
t.Fatalf("DeriveAddresses failed: %v", err)
}
// Map of known addresses for the test mnemonic
knownAddresses := map[string]string{
"m/44'/0'/0'/0/0": "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA",
"m/44'/0'/0'/0/1": "1Ak8PffB2meyfYnbXZR9EGfLfFZVpzJvQP",
"m/49'/0'/0'/0/0": "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf",
"m/84'/0'/0'/0/0": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu",
"m/84'/0'/0'/0/1": "bc1qnjg0jd8228aq7egyzacy8cys3knf9xvrerkf9g",
}
addressMap := make(map[string]string)
for _, addr := range addresses {
addressMap[addr.Path] = addr.Address
}
for path, expectedAddr := range knownAddresses {
actualAddr, exists := addressMap[path]
if !exists {
t.Errorf("Address for path %s not found", path)
continue
}
if actualAddr != expectedAddr {
t.Errorf("Address mismatch for path %s:\n expected: %s\n got: %s",
path, expectedAddr, actualAddr)
} else {
t.Logf("✓ %s = %s", path, actualAddr)
}
}
}
func TestMnemonicValidation(t *testing.T) {
tests := []struct {
name string
mnemonic string
valid bool
}{
{
name: "Valid 12-word mnemonic",
mnemonic: testMnemonic,
valid: true,
},
{
name: "Invalid mnemonic",
mnemonic: "invalid mnemonic phrase that should not work",
valid: false,
},
{
name: "Empty mnemonic",
mnemonic: "",
valid: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
valid := bip39.IsMnemonicValid(tt.mnemonic)
if valid != tt.valid {
t.Errorf("Expected mnemonic validity to be %v, got %v", tt.valid, valid)
}
})
}
}
func TestPassphraseSupport(t *testing.T) {
// Test that different passphrases generate different seeds
seed1 := bip39.NewSeed(testMnemonic, "")
seed2 := bip39.NewSeed(testMnemonic, "password123")
if string(seed1) == string(seed2) {
t.Error("Seeds with different passphrases should be different")
}
// Verify that addresses are different with different passphrases
addresses1, err := bitcoin.DeriveAddresses(seed1, 1)
if err != nil {
t.Fatalf("DeriveAddresses failed for seed1: %v", err)
}
addresses2, err := bitcoin.DeriveAddresses(seed2, 1)
if err != nil {
t.Fatalf("DeriveAddresses failed for seed2: %v", err)
}
if len(addresses1) == 0 || len(addresses2) == 0 {
t.Fatal("No addresses generated")
}
if addresses1[0].Address == addresses2[0].Address {
t.Error("Addresses should be different with different passphrases")
}
t.Logf("Without passphrase: %s", addresses1[0].Address)
t.Logf("With passphrase: %s", addresses2[0].Address)
}

View File

@@ -0,0 +1,67 @@
package types
import "time"
// Chain represents a blockchain type
type Chain string
const (
ChainBitcoin Chain = "bitcoin"
ChainEthereum Chain = "ethereum"
)
// AddressInfo contains information about a derived address
type AddressInfo struct {
Address string
Path string
Balance uint64
TxCount int
Chain Chain
Received uint64
Sent uint64
}
// Transaction represents a blockchain transaction
type Transaction struct {
TxID string
Time time.Time
BlockHeight int
Confirmed bool
Received uint64
Sent uint64
Fee uint64
NetChange int64 // Can be negative
Addresses []string
}
// TransactionDetail provides detailed transaction information
type TransactionDetail struct {
TxID string
Time time.Time
BlockHeight int
Confirmed bool
Type string // "received", "sent", "self"
Amount uint64
Balance uint64 // Running balance after this tx
Address string
}
// WalletSummary contains overall wallet statistics
type WalletSummary struct {
TotalBalance uint64
TotalReceived uint64
TotalSent uint64
TotalTxCount int
ReceiveTxCount int
SendTxCount int
ActiveAddresses []AddressInfo
TransactionHistory []TransactionDetail
}
// ChainAnalyzer defines the interface for blockchain analysis
type ChainAnalyzer interface {
DeriveAddresses(seed []byte, count int) ([]AddressInfo, error)
GetAddressInfo(address string) (balance, txCount uint64, received, sent uint64, err error)
GetTransactions(address string) ([]Transaction, error)
GetChain() Chain
}

0
cat-unless-older/cat-unless-older Executable file → Normal file
View File

0
checkcert/checkcert Executable file → Normal file
View File

0
clean-old-osx-homedir/cleanhomedir Executable file → Normal file
View File

0
coldbackup/dobackup.sh Executable file → Normal file
View File

0
cronify/cronify Executable file → Normal file
View File

0
dump-imessages/dump.sh Executable file → Normal file
View File

0
dump-imessages/iphone-dataprotection/build_ramdisk.sh Executable file → Normal file
View File

View File

0
dump-imessages/iphone-dataprotection/build_tools.sh Executable file → Normal file
View File

View File

View File

0
dump-imessages/iphone-dataprotection/tcprelay.sh Executable file → Normal file
View File

View File

0
email-to-webhook/email_to_webhook Executable file → Normal file
View File

0
fetchtweets/fetchtweets Executable file → Normal file
View File

0
findmastos/findmastos.py Executable file → Normal file
View File

0
fix-raspian-defaults/install-to-boot.sh Executable file → Normal file
View File

View File

0
forward-email-to-slack-webhook/email_to_webhook Executable file → Normal file
View File

0
forward-email-to-slack-webhook/install.sh Executable file → Normal file
View File

0
geolocate/geolocate.py Executable file → Normal file
View File

0
geolocate/weather.py Executable file → Normal file
View File

0
goshebang/test.go Executable file → Normal file
View File

0
grandcentral-vm-downloader/gc-vm-email-download.pl Executable file → Normal file
View File

View File

@@ -1,82 +0,0 @@
JUNKFILES = .bash_history .irb_history .pip .ScanSnap .nbems .fldigi .cpan
JUNKFILES += .gdb_history .mysql_history .sqlite_history
BREWPACKAGES := mosh duplicity pv offlineimap wget nmap tor torsocks
YYYYMM := $(shell date +%Y-%m)
HACKSREPO := ~/.paths/sneak-scratch/dev/hacks/
NO_COLOR = \033[0m
O1_COLOR = \033[0;01m
O2_COLOR = \033[32;01m
PREFIX = "$(O2_COLOR)==>$(O1_COLOR)"
SUFFIX = "$(NO_COLOR)"
default: routine
# FIXME make this do a local imap download too
routine: clean databackup
backup: clean mailoffsite databackup
dvbackup:
@echo $(PREFIX) $@ $(SUFFIX)
cd ~/Documents/datavibe/backup && make
imapbackup:
offlineimap
rsync -e "ssh -o Compression=no -x" \
-avPhzy --delete-after sneak@datavibe.net:.maildir/ \
$(HOME)/Documents/Archival/mail/sneak.datavibe.net.maildir/
mailoffsite: imapbackup
rsync -e "ssh -o Compression=no -x" \
-avPhzy --delete-after $(HOME)/Documents/Archival/mail/ \
sneak@datavibe.net:.mailbackup/
tar -xvf $(HOME)/Documents/Archival/mail/jp.eeqj.com | gzip > \
$(HOME)/Documents/Dropbox/eeqj/archives/mail.tgz.new && \
mv $(HOME)/Documents/Dropbox/eeqj/archives/mail.tgz.new \
$(HOME)/Documents/Dropbox/eeqj/archives/mail.tgz
databackup:
~/dev/hacks/bin/backup.command
cleanup:
-mkdir -p $(HOME)/Documents/$(YYYYMM)
-mv $(HOME)/Desktop/* $(HOME)/Documents/$(YYYYMM)
clean: cleanup
@echo $(PREFIX) $@ $(SUFFIX)
@-rm -rf ~/.tmp/*
@-rm -rf ~/.Trash/*
@-rm -rf ~/Library/Google
@-rm -rf ~/Library/ApplicationSupport/Google/RLZ
@-rm -rf $(JUNKFILES)
size:
du -sh $(HOME)
lifeboat:
mkdir -p $(HOME)/tmp/lifeboat.$(YYYYMM)
rsync -avP --exclude='*.pkg' $(HOME)/Documents/Secure/ \
$(HOME)/tmp/lifeboat.$(YYYYMM)/Secure/
rsync -avP $(HOME)/Library/ApplicationSupport/Bitcoin/wallet.dat \
$(HOME)/tmp/lifeboat.$(YYYYMM)/wallet.dat
tar -c $(HOME)/tmp/lifeboat.$(YYYYMM) | bzip2 | \
gpg --symmetric -a -o $(HOME)/lifeboat.$(YYYYMM).gpg
rm -rf $(HOME)/tmp/lifeboat.$(YYYYMM)
cp $(HOME)/lifeboat.$(YYYYMM).gpg \
$(HOME)/dev/eeqjcdn/sneak.datavibe.net/lifeboat/lifeboat.gpg
cd $(HOME)/dev/eeqjcdn && make
mv $(HOME)/lifeboat.$(YYYYMM).gpg $(HOME)/Documents/Dropbox/Backups/
verify:
duplicity verify --exclude-globbing-filelist \
$(HOME)/.local/etc/duplicity.exclude \
file:///Volumes/EXTUSB01/dup/ ~
remotebackup:
RBACKUPDEST="scp://jp.eeqj.de/backup" $(HOME)/.local/bin/backup.command
update:
ln -s $(HACKSREPO)/homedir.makefile/Makefile $(HOME)/Makefile

View File

@@ -1,22 +0,0 @@
#!/bin/bash
DEST="/Volumes/video"
D="root@las1"
function main() {
if [[ ! -d "$DEST/2022" ]]; then
echo "wrong box" > /dev/stderr
exit 1
fi
SRC="$1"
cd "$SRC"
for FILE in * ; do
YYYY="$(echo "$FILE" | colrm 5)"
MM="$(echo "$FILE" | colrm 1 4 | colrm 3)"
DD="$(echo "$FILE" | colrm 1 6 | colrm 3)"
echo "ssh $D -- mkdir -p /storage/video/$YYYY/$YYYY-$MM/$YYYY-$MM-$DD"
echo "rsync -acvvvP \"$SRC/$FILE\" $D:/storage/video/$YYYY/$YYYY-$MM/$YYYY-$MM-$DD/"
done
}
main $*

View File

@@ -0,0 +1,25 @@
TARGET := ./berlin.sneak.fs.NNNY-cyberdyne-backup-01
default: backup
backup: do_file_backup write_checksum
write_checksum:
cd $(TARGET)/fs && find . -type f -print0 | xargs -0 sha1sum > ../.SHASUMS.tmp
mv ./.SHASUMS.tmp ./$(TARGET)/SHASUMS.txt
do_file_backup:
rsync -avv \
--exclude=/tmp \
--exclude=/.cache \
--exclude=/.nvm \
--exclude=/.Trash \
--exclude=/Library/Caches \
--exclude=/Library/Mail \
--exclude=/Library/Developer \
--exclude=.DS_Store \
--delete-before \
--delete-excluded \
$(HOME)/ $(TARGET)/fs/ 2>&1 | tee -a $(TARGET)/$(shell date -u +%Y-%m-%d).log
echo '# $(shell date -u)' > $(TARGET)/lastbackup.txt
date -u '+%s' >> $(TARGET)/lastbackup.txt

View File

@@ -0,0 +1,16 @@
THIS = $(shell basename $(CURDIR))
YYYYMMDD = $(shell date -u +%Y-%m-%d)
YYYY = $(shell date +%Y)
default: save_makefile update-lifeboat update-photos
save_makefile:
cp ./Makefile $(HOME)/dev/hacks/makefiles/$(YYYYMMDD).$(THIS).makefile
update-lifeboat:
rsync -avP --delete $(HOME)/Library/Syncthing/folders/lifeboat/*.zip /Volumes/1tb-lifeboat1G/berlin.sneak.fs.lifeboat/
zip -T /Volumes/1tb-lifeboat1G/berlin.sneak.fs.lifeboat/*.zip
update-photos:
rsync -avP --delete $(HOME)/Library/Syncthing/folders/LightroomMasters-CurrentYear/ ./fs/ 2>&1 | tee -a log.txt
cd ./fs && find . -type f -print0 | xargs -0 shasum 2&>1 | tee -a ../SHASUMS.txt

View File

@@ -0,0 +1,28 @@
THIS = $(shell basename $(CURDIR))
YYYYMMDD = $(shell date -u +%Y-%m-%d)
default: backup
save_makefile:
cp ./Makefile $(HOME)/dev/hacks/makefiles/$(YYYYMMDD).$(THIS).makefile
backup: save_makefile do_file_backup write_checksum
write_checksum:
cd ./fs && find . -type f -print0 | xargs -0 sha1sum | tee -a ../SHASUMS.txt
do_file_backup:
rsync -avv \
--exclude=/tmp \
--exclude=/.cache \
--exclude=/.nvm \
--exclude=/.Trash \
--exclude=/Library/Caches \
--exclude=/Library/Mail \
--exclude=/Library/Developer \
--exclude=.DS_Store \
--delete-before \
--delete-excluded \
$(HOME)/ ./fs/ 2>&1 | tee -a ./$(shell date -u +%Y-%m-%d).log
echo '# $(shell date -u)' > ./lastbackup.txt
date -u '+%s' >> ./lastbackup.txt

View File

@@ -0,0 +1,10 @@
THIS = usbroot-makefile
YYYYMMDD = $(shell date -u +%Y-%m-%d)
default: save_makefile alldirs
save_makefile:
cp ./Makefile $(HOME)/dev/hacks/makefiles/$(YYYYMMDD).$(THIS).makefile
alldirs:
for D in ./berlin.sneak.fs.* ; do cd $$D && make && cd .. ; done

View File

@@ -0,0 +1,40 @@
HOMEEXCLUDE := --exclude /.Trash \
--exclude .DS_Store \
--exclude /.Spotlight-V100 \
--exclude /.cache \
--exclude /.fseventsd \
--exclude /Library/Caches \
--exclude /Library/Mail \
--exclude /Library/Metadata/CoreSpotlight \
--exclude /tmp
ROOTEXCLUDE := --exclude /.Trash \
--exclude /proc \
--exclude /dev \
--exclude /.fseventsd \
--exclude .DS_Store \
--exclude /System/Volumes/Data/Volumes \
--exclude /private/var/vm \
--exclude /System/Volumes/Data/nix \
--exclude /System/Volumes/Data/Users/sneak \
--exclude /Users/sneak \
--exclude /System/Volumes/Data/.fseventsd \
--exclude /System/Volumes/Data/.Spotlight-V100 \
--exclude /System/Volumes/Data/private/var/folders \
--exclude /private/var/folders \
--exclude /Volumes
OPTS := -avP --delete --delete-excluded --delete-before
HOMEOPTS := $(OPTS) $(HOMEEXCLUDE)
ROOTOPTS := $(OPTS) $(ROOTEXCLUDE)
default:
sudo bash -c 'make synchome; make syncroot'
synchome:
rsync $(HOMEOPTS) $(HOME)/ ./2021-01-12.nostromo.sneakhome/ | tee -a $(shell date +%Y-%m-%d).homesync.log
syncroot:
rsync $(ROOTOPTS) / ./2021-01-12.nostromo.root/ | tee -a $(shell date +%Y-%m-%d).rootsync.log

48
mastodon-s3-move/Makefile Normal file
View File

@@ -0,0 +1,48 @@
PAR := 50
default: dl
dl:
rclone copy \
--progress \
--transfers $(PAR) \
--stats-unit bits \
--retries 10 \
--retries-sleep 60s \
--checkers $(PAR) \
--fast-list \
--s3-list-chunk 5000 \
--s3-disable-http2 \
--s3-sdk-log-mode Request,Response \
--no-traverse \
--check-first \
-vv --log-file=rclone-log-202505.txt \
mastodon-nbg1-s3:mastodon/ las1stor1-files:/srv/berlin.sneak.fs.mastodon-media/mastodon-bucket/
downloadold:
rclone copy \
--progress \
--transfers $(PAR) \
--stats-unit bits \
--retries 10 \
--retries-sleep 60s \
--fast-list \
--checkers=$(PAR) \
--check-first \
-vv --log-file=rclone-log.txt \
mastodon-nbg1-s3:mastodon/ ./mastodon-bucket/
copy:
rclone copy \
-v -v -v \
--progress \
--transfers $(PAR) \
--stats-unit bits \
--retries 10 \
--retries-sleep 60s \
--fast-list \
--checkers $(PAR) \
--check-first \
--log-file=rclone-copy-las1stor1.txt \
./ \
las1stor1-files:/srv/berlin.sneak.fs.mastodon-media/

0
misc/startsession Executable file → Normal file
View File

0
mtgox.tradescraper/dailyprice.pl Executable file → Normal file
View File

0
mtgox.tradescraper/scrape.py Executable file → Normal file
View File

8
nmeastream/main.py Normal file
View File

@@ -0,0 +1,8 @@
from serial import Serial
from pynmeagps import NMEAReader
with Serial('/dev/tty.usbmodem314101', 9600, timeout=3) as stream:
nmr = NMEAReader(stream)
raw_data, parsed_data = nmr.read()
if parsed_data is not None:
print(parsed_data)

156
nmeastream/nmeapoller.py Normal file
View File

@@ -0,0 +1,156 @@
"""
nmeapoller.py
This example illustrates how to read, write and display NMEA messages
"concurrently" using threads and queues. This represents a useful
generic pattern for many end user applications.
Usage:
python3 nmeapoller.py port=/dev/ttyACM0 baudrate=38400 timeout=3
It implements two threads which run concurrently:
1) an I/O thread which continuously reads NMEA data from the
receiver and sends any queued outbound command or poll messages.
2) a process thread which processes parsed NMEA data - in this example
it simply prints the parsed data to the terminal.
NMEA data is passed between threads using queues.
Press CTRL-C to terminate.
FYI: Since Python implements a Global Interpreter Lock (GIL),
threads are not strictly concurrent, though this is of minor
practical consequence here.
Created on 07 Aug 2021
:author: semuadmin
:copyright: SEMU Consulting © 2021
:license: BSD 3-Clause
"""
from queue import Queue
from sys import argv
from threading import Event, Thread
from time import sleep
from serial import Serial
from pynmeagps import NMEA_MSGIDS, POLL, NMEAMessage, NMEAReader
def io_data(
stream: object,
nmr: NMEAReader,
readqueue: Queue,
sendqueue: Queue,
stop: Event,
):
"""
THREADED
Read and parse inbound NMEA data and place
raw and parsed data on queue.
Send any queued outbound messages to receiver.
"""
# pylint: disable=broad-exception-caught
while not stop.is_set():
try:
if stream.in_waiting:
(raw_data, parsed_data) = nmr.read()
if parsed_data:
readqueue.put((raw_data, parsed_data))
if not sendqueue.empty():
data = sendqueue.get(False)
if data is not None:
nmr.datastream.write(data.serialize())
sendqueue.task_done()
except Exception as err:
print(f"\n\nSomething went wrong {err}\n\n")
continue
def process_data(queue: Queue, stop: Event):
"""
THREADED
Get NMEA data from queue and display.
"""
while not stop.is_set():
if queue.empty() is False:
(_, parsed) = queue.get()
print(parsed)
queue.task_done()
def main(**kwargs):
"""
Main routine.
"""
port = kwargs.get("serport", "/dev/ttyACM0")
baudrate = int(kwargs.get("baudrate", 38400))
timeout = float(kwargs.get("timeout", 3))
with Serial(port, baudrate, timeout=timeout) as serial_stream:
nmeareader = NMEAReader(serial_stream)
read_queue = Queue()
send_queue = Queue()
stop_event = Event()
io_thread = Thread(
target=io_data,
args=(
serial_stream,
nmeareader,
read_queue,
send_queue,
stop_event,
),
)
process_thread = Thread(
target=process_data,
args=(
read_queue,
stop_event,
),
)
print("\nStarting handler threads. Press Ctrl-C to terminate...")
io_thread.start()
process_thread.start()
# loop until user presses Ctrl-C
while not stop_event.is_set():
try:
# DO STUFF IN THE BACKGROUND...
# Poll for each NMEA sentence type.
# NB: Your receiver may not support all types. It will return a
# GNTXT "NMEA unknown msg" response for any types it doesn't support.
for msgid in NMEA_MSGIDS:
print(
f"\nSending a GNQ message to poll for an {msgid} response...\n"
)
msg = NMEAMessage("EI", "GNQ", POLL, msgId=msgid)
send_queue.put(msg)
sleep(1)
sleep(3)
stop_event.set()
except KeyboardInterrupt: # capture Ctrl-C
print("\n\nTerminated by user.")
stop_event.set()
print("\nStop signal set. Waiting for threads to complete...")
io_thread.join()
process_thread.join()
print("\nProcessing complete")
if __name__ == "__main__":
main(**dict(arg.split("=") for arg in argv[1:]))

0
osxbackup/appbackup.command Executable file → Normal file
View File

0
osxbackup/backup.command Executable file → Normal file
View File

6
osxbackup/rsyncbackup.command Executable file → Normal file
View File

@@ -46,10 +46,8 @@ RE+=" --exclude=/.local/share/containers/podman/machine/"
RE+=" --exclude=/.dropbox/"
RE+=" --exclude=/.minikube/cache/"
RE+=" --exclude=/Applications/Fortnite/"
RE+=" --exclude=/Desktop/" # desktop is like a visible tempdir.
RE+=" --exclude=/Documents/Dropbox/.dropbox.cache/"
RE+=" --exclude=/Documents/Steam?Content/"
RE+=" --exclude=/Downloads/"
RE+=" --exclude=/Library/Application?Support/Ableton/"
RE+=" --exclude=/Library/Application?Support/Adobe/Adobe?Device?Central?CS4/"
RE+=" --exclude=/Library/Application?Support/CrossOver?Games/"
@@ -64,6 +62,7 @@ RE+=' --exclude=/Library/Application?Support/Syncthing/index-*'
RE+=" --exclude=/Library/Metadata"
RE+=" --exclude=/Library/Caches/"
RE+=" --exclude=/Library/Containers/com.docker.docker/"
RE+=" --exclude=/Library/Group?Containers/group.com.apple.secure-control-center-preferences"
RE+=" --exclude=/Library/Cookies/"
RE+=" --exclude=/Library/Developer/"
RE+=" --exclude=/Library/Google/GoogleSoftwareUpdate/"
@@ -72,6 +71,7 @@ RE+=" --exclude=/Library/Logs/"
RE+=" --exclude=/Library/Mail/" # keep your mail on the server!
RE+=" --exclude=/Library/Mail?Downloads/"
RE+=" --exclude=/Library/Parallels/"
RE+=" --exclude=/Library/Suggestions/"
RE+=" --exclude=/Library/Preferences/Macromedia/Flash?Player/"
RE+=" --exclude=/Library/Preferences/SDMHelpData/"
RE+=" --exclude=/Library/PubSub/"
@@ -86,6 +86,7 @@ RE+=" --exclude=/Movies/ProxyMedia/"
RE+=" --exclude=/Music/iTunes/Album?Artwork/"
RE+=" --exclude=/Pictures/iPod?Photo?Cache/"
RE+=" --exclude=/Receivd/"
RE+=" --exclude=/.persepolis/"
MINRE=""
MINRE+=" --exclude=/.fseventsd/"
@@ -153,6 +154,7 @@ RE+=" --exclude=/Stickies.app"
RE+=" --exclude=/System?Preferences.app"
RE+=" --exclude=/TextEdit.app"
RE+=" --exclude=/Time?Machine.app"
RE+=" --exclude=/Yubikey?Manager.app"
RE+=" --exclude=/Utilities/Activity?Monitor.app"
RE+=" --exclude=/Utilities/AirPort?Utility.app"
RE+=" --exclude=/Utilities/AppleScript?Editor.app"

0
osxubuntumirror/debmirror.sh Executable file → Normal file
View File

0
osxubuntumirror/syncubuntu.sh Executable file → Normal file
View File

0
pgoatp/pgoatp.pl Executable file → Normal file
View File

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env zsh
set -x
set -e
set -o nullglob
YYYYMMDD="$(date "+%Y-%m-%d")"
RSYNCOPTS="-ah --no-inc-recursive --info=progress2"
RDST="root@las1stor1:/srv/pool.2024.04/berlin.sneak.fs.video"
function amLocalToVideoStore() {
ifconfig | grep 10.100.205 | wc -l
}
function copyVideosToVideoStore() {
rsync \
-ah --no-inc-recursive --info=progress2 \
./ "$RDST"/ && \
rsync \
-ah --no-inc-recursive --info=progress2 \
--remove-source-files \
./ "$RDST"/ && \
rm -rfv ./ && \
}
function main() {
if [[ $(amLocalToLAS1) -gt 0 ]]; then
copyVideosToLAS1
fi
}
main

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env zsh
set -x
set -e
set -o nullglob
YYYYMMDD="$(date "+%Y-%m-%d")"
DST="$HOME/_TODO/$YYYYMMDD-video-import"
RSYNCOPTS="-ah --no-inc-recursive --info=progress2"
RDST="root@las1stor1:/srv/pool.2024.04/berlin.sneak.fs.video"
function amLocalToLAS1() {
ifconfig | grep 10.100.205 | wc -l
}
function copyVideosToLAS1() {
rsync \
-ah --no-inc-recursive --info=progress2 \
"$DST"/ "$RDST"/ && \
rsync \
-ah --no-inc-recursive --info=progress2 \
--remove-source-files \
"$DST"/ "$RDST"/ && \
rm -rfv "$DST" && \
ssh root@las1stor1 "cd /srv/pool.2024.04/berlin.sneak.fs.video && chown -R nobody:nogroup ."
}
function main() {
if [[ $(amLocalToLAS1) -gt 0 ]]; then
copyVideosToLAS1
fi
}
main

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env zsh
set -x
set -e
set -o nullglob
YYYYMMDD="$(date "+%Y-%m-%d")"
RSYNCOPTS="-ah --no-inc-recursive --info=progress2"
RDST="root@las1stor1:/srv/pool.2024.04/berlin.sneak.fs.video"
function rename_to_format() {
f2 -r '{{mtime.YYYY}}/{{mtime.YYYY}}-{{mtime.MM}}/{{mtime.YYYY}}-{{mtime.MM}}-{{mtime.DD}}/{{mtime.YYYY}}-{{mtime.MM}}-{{mtime.DD}}.{{f}}.{{hash.sha256}}{{ext}}' -x --verbose
}
function import() {
rename_to_format
rsync -avP ./2* $RDST/
}
function main() {
import
}
main

19
photoimport/photoimport Executable file → Normal file
View File

@@ -5,14 +5,13 @@ set -o nullglob
YYYYMMDD="$(date "+%Y-%m-%d")"
function downloadPhotos() {
SRC=(/Volumes/*/DCIM)
if [[ ! -d "$SRC" ]]; then
echo "no photos" > /dev/stderr
return
fi
DST="$HOME/Library/Syncthing/folders/LightroomMasters-CurrentYear/toimport"
DST="$HOME/Pictures/_ORIG"
du -sh "$SRC"
rsync -ah --no-inc-recursive --info=progress2 --remove-source-files "$SRC"/ $DST/$YYYYMMDD/
cd "$DST/$YYYYMMDD"
@@ -20,26 +19,10 @@ function downloadPhotos() {
f2 -r '../{{mtime.YYYY}}/{{mtime.YYYY}}-{{mtime.MM}}/{{mtime.YYYY}}-{{mtime.MM}}-{{mtime.DD}}/{{mtime.YYYY}}-{{mtime.MM}}-{{mtime.DD}}.{{x.model}}.{{f}}.{{hash.sha256}}{{ext}}' -x --verbose
}
function downloadVideos() {
SRC=(/Volumes/*/PRIVATE/M4ROOT/CLIP)
if [[ ! -d "$SRC" ]]; then
echo "no videos" > /dev/stderr
return
fi
DST="$HOME/_TODO/$YYYYMMDD-video-import/"
mkdir -p "$DST"
du -sh "$SRC"
rsync -ah --no-inc-recursive --info=progress2 --remove-source-files "$SRC"/ $DST/
cd "$DST"
#mv */* .
f2 -r '{{mtime.YYYY}}/{{mtime.YYYY}}-{{mtime.MM}}/{{mtime.YYYY}}-{{mtime.MM}}-{{mtime.DD}}/{{mtime.YYYY}}-{{mtime.MM}}-{{mtime.DD}}.{{f}}.{{hash.sha256}}{{ext}}' -x --verbose
}
function main() {
# FIXME this doesn't work if there are no photos on the card but the
# DCIM dir exists
downloadPhotos
downloadVideos
}
main

44
photoimport/videoimport Normal file
View File

@@ -0,0 +1,44 @@
#!/usr/bin/env zsh
set -x
set -e
set -o nullglob
YYYYMMDD="$(date "+%Y-%m-%d")"
DST="$HOME/_TODO/$YYYYMMDD-video-import"
RSYNCOPTS="-ah --no-inc-recursive --info=progress2"
LASDST="root@las1:/srv/las1/video"
function downloadVideos() {
SRC=(/Volumes/*/PRIVATE/M4ROOT/CLIP)
if [[ ! -d "$SRC" ]]; then
echo "no videos" > /dev/stderr
exit 1
fi
if [[ ! -n "$(ls -A "$SRC" 2>/dev/null)" ]]; then
echo "no videos" > /dev/stderr
exit 1
fi
mkdir -p "$DST"
du -sh "$SRC"
rsync \
-ah --no-inc-recursive --info=progress2 \
--remove-source-files "$SRC"/ $DST/
cd "$DST"
#mv */* .
f2 -r '{{mtime.YYYY}}/{{mtime.YYYY}}-{{mtime.MM}}/{{mtime.YYYY}}-{{mtime.MM}}-{{mtime.DD}}/{{mtime.YYYY}}-{{mtime.MM}}-{{mtime.DD}}.{{f}}.{{hash.sha256}}{{ext}}' -x --verbose
}
function amLocalToLAS1() {
ifconfig | grep 10.100.205 | wc -l
}
function main() {
# FIXME this doesn't work if there are no photos on the card but the
# DCIM dir exists
downloadVideos
}
main

48
photomigrate/photomigrate Normal file
View File

@@ -0,0 +1,48 @@
#!/usr/bin/env zsh
LOGFILE="$HOME/tmp/photocopylog.txt"
exec &> >(tee -a "$LOGFILE")
set -x
DST="user@nostromo2.local:/Volumes/berlin.sneak.fs.photostore"
date
date -u
time rsync \
-avvh --no-inc-recursive --info=progress2 \
"$HOME/Library/Syncthing/folders/LightroomMasters-PastYears/" \
"$DST/berlin.sneak.fs.photostore-PastYears/"
date
date -u
time rsync \
-avvh --no-inc-recursive --info=progress2 \
"$HOME/Library/Syncthing/folders/LightroomMasters-CurrentYear/" \
"$DST/berlin.sneak.fs.photostore-CurrentYear/"
exit 0
date
date -u
time rsync \
-acvvh --no-inc-recursive --info=progress2 \
"$HOME/Library/Syncthing/folders/LightroomMasters-PastYears/" \
"$DST/berlin.sneak.fs.photostore-PastYears/"
date
date -u
time rsync \
-acvvh --no-inc-recursive --info=progress2 \
"$HOME/Library/Syncthing/folders/LightroomMasters-CurrentYear/" \
"$DST/berlin.sneak.fs.photostore-CurrentYear/"
date
date -u

0
rsync.workstation.backup/media-backup.sh Executable file → Normal file
View File

0
run-aws-job/run-job Executable file → Normal file
View File

0
scrapers/amexscraper.py Executable file → Normal file
View File

0
scrapers/etradescraper.py Executable file → Normal file
View File

0
scrapers/scraper.py Executable file → Normal file
View File

0
tweetbackup/go/tweetbackup Executable file → Normal file
View File

0
update-workstation-location/update-location-json.sh Executable file → Normal file
View File

0
vimrc/install.sh Executable file → Normal file
View File

0
vmprov/packages.txt Executable file → Normal file
View File

122
waku2/go.mod Normal file
View File

@@ -0,0 +1,122 @@
module waku2chat
go 1.20
require (
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
github.com/beevik/ntp v0.3.0 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cruxic/go-hmac-drbg v0.0.0-20170206035330-84c46983886d // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/elastic/gosigar v0.14.2 // indirect
github.com/ethereum/go-ethereum v1.10.26 // indirect
github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/go-ole/go-ole v1.2.1 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect
github.com/huin/goupnp v1.2.0 // indirect
github.com/ipfs/go-cid v0.4.1 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/koron/go-ssdp v0.0.4 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
github.com/libp2p/go-libp2p v0.29.2 // indirect
github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect
github.com/libp2p/go-libp2p-pubsub v0.9.3 // indirect
github.com/libp2p/go-mplex v0.7.0 // indirect
github.com/libp2p/go-msgio v0.3.0 // indirect
github.com/libp2p/go-nat v0.2.0 // indirect
github.com/libp2p/go-netroute v0.2.1 // indirect
github.com/libp2p/go-reuseport v0.3.0 // indirect
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/miekg/dns v1.1.55 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multiaddr v0.10.1 // indirect
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect
github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-multistream v0.4.1 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-19 v0.3.3 // indirect
github.com/quic-go/qtls-go1-20 v0.2.3 // indirect
github.com/quic-go/quic-go v0.36.4 // indirect
github.com/quic-go/webtransport-go v0.5.3 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rjeczalik/notify v0.9.3 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tklauser/go-sysconf v0.3.5 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 // indirect
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20230628220917-7b4e5ae4c0e7 // indirect
github.com/waku-org/go-waku v0.9.0 // indirect
github.com/waku-org/go-zerokit-rln v0.1.14-0.20230916173259-d284a3d8f2fd // indirect
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b // indirect
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065 // indirect
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20230916171518-2a77c3734dd1 // indirect
github.com/wk8/go-ordered-map v1.0.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/dig v1.17.0 // indirect
go.uber.org/fx v1.20.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/tools v0.12.1-0.20230818130535-1517d1a3ba60 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
lukechampine.com/blake3 v1.2.1 // indirect
)

Some files were not shown because too many files have changed in this diff Show More