The share.go module handles generation of secure share strings that allow users to share individual files from their vault without exposing the entire vault or requiring the recipient to know the vault password.
File: utils/share.go
Generates a shareable access token for a specific file in the vault.
Signature:
func ShareFile(vaultPath string, session *Session) (string, error)Parameters:
vaultPath(string): Path to the file within the vault (e.g.,documents/report.pdf)session(*Session): Active session containing username, password, and decrypted index
Returns:
string: Share string in formatusername:storage_id:hex_encoded_file_keyerror: Non-nil if file not found, decryption fails, or index is corrupted
Behavior:
- Locate File: Searches the vault index for the file at
vaultPath - Decrypt Key: Retrieves the encrypted per-file key from the index entry
- Verify Password: Decrypts the file key using the vault password (PBKDF2 key derivation)
- Encode Key: Converts the raw 32-byte file key to hexadecimal for transmission
- Format String: Constructs and returns:
{username}:{storage_id}:{hex_file_key}
Example Usage:
session := &Session{
Username: "john",
Password: "vault_password",
Index: vaultIndex,
}
shareString, err := ShareFile("documents/report.pdf", session)
if err != nil {
log.Fatal(err)
}
fmt.Println(shareString)
// Output: john:a3f2e1c9:abc123def456789abc123def456789abusername:storage_id:decryption_key
Components:
username: GitHub username of the vault ownerstorage_id: Unique identifier for the file in the vault (hex-encoded)decryption_key: Hexadecimal-encoded 32-byte per-file encryption key
john:a3f2e1c9d4b6f8e2:5a7e9c3b1f8d4a2e6b9c1d8e5a7b3c4f
- File Key: The per-file encryption key, allowing decryption of that specific file
- Storage ID: The unique identifier where the file is stored
- Username: The vault owner's GitHub username
- ❌ Vault password
- ❌ SSH private key
- ❌ Other files in the vault
- ❌ Vault index structure
- ❌ Access to any other vault operations
Shared files cannot be unshared without changing the file:
- If you want to revoke access, delete and re-upload the file with new content
- This generates a new per-file key and storage ID
- Previous share strings become invalid
- The file has a new share string for future sharing
Note: Once shared, you cannot track who has the share string or when it's used.
./zep share <vault-path>Alias: sh
The share CLI command calls ShareFile() and displays the result:
var shareCmd = &cobra.Command{
Use: "share [vault-path]",
Aliases: []string{"sh"},
Short: "Generate a share string for a file",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
session, err := getEffectiveSession()
if err != nil {
log.Fatal(err)
}
shareString, err := utils.ShareFile(args[0], session)
if err != nil {
log.Fatal(err)
}
fmt.Println("Share this string to allow others to download the file:")
fmt.Println(shareString)
fmt.Printf(" zep download _ output.file --shared \"%s\"\n", shareString)
},
}-
Generate Share String
./zep share documents/report.pdf
-
Get Output
Share this string to allow others to download the file: john:a3f2e1c9:5a7e9c3b1f8d4a2e6b9c1d8e5a7b3c4f Recipient can download with: zep download _ output.file --shared "john:a3f2e1c9:5a7e9c3b1f8d4a2e6b9c1d8e5a7b3c4f" -
Share Securely
- Use encrypted email, password manager, or secure messaging
- Never share via plain email or unencrypted channels
- Document recipients for security audit purposes
- Receive Share String (via secure channel)
- Download Shared File
./zep download _ report.pdf --shared "john:a3f2e1c9:5a7e9c3b1f8d4a2e6b9c1d8e5a7b3c4f" - File is decrypted using the provided per-file key
| Error | Cause | Solution |
|---|---|---|
path not found |
File doesn't exist at vault path | Use ls or search to find correct path |
is a directory |
Specified path is a folder | Share a specific file within the folder |
decryption failed |
Wrong vault password in session | Reconnect with correct password |
invalid index |
Corrupted vault index | Re-run setup or check repository |
File keys are stored in the vault index encrypted with the vault password:
File Key (32 bytes)
↓
[Vault Password: PBKDF2-SHA256 × 100,000]
↓
AES-256-GCM Encryption
↓
Encrypted Key (stored in index)
Raw bytes are converted to hexadecimal for the share string:
hex.EncodeToString(fileKey[:]) // 32 bytes → 64 hex characters- upload.go -
GenerateFileKey()creates per-file keys - encryption.go -
EncodeKey()converts keys to hex - download.go -
DownloadSharedFile()uses share strings - index.go -
FindEntry()locates files in vault
✅ Good Use Cases:
- Share a single report with a colleague
- Send a file to a client without exposing vault
- Allow team member to access one document
- Share medical records with a provider
❌ Avoid:
- Sharing via unencrypted email
- Including share string in chat messages
- Posting in public channels
- Sharing with untrusted recipients
- Long-term file access (share expires when file changes)
- Use secure channel to share the string
- Document who received the share
- Set reminder to revoke if needed
- Re-upload file monthly to rotate keys
- Delete old files to prevent accidental sharing
Time Complexity: O(n) where n = depth of file path in index tree
- Index lookup: O(n) traversal
- Decryption: O(1) constant time per file key
- Encoding: O(1) for 32-byte key
Network I/O: None (operation is local on decrypted index)
Planned improvements for file sharing:
- Share Expiration: Auto-expire share strings after N days
- Download Tracking: Record who downloads via share string
- Access Limits: Limit share to N downloads
- ACLs: Share with multiple users under access control list
- Revocation Log: Track revocations and invalidated shares
func TestShareFile(t *testing.T) {
session := &Session{
Username: "testuser",
Password: "password123",
Index: testIndex,
}
shareString, err := ShareFile("test/file.pdf", session)
if err != nil {
t.Fatal(err)
}
// Verify format
parts := strings.Split(shareString, ":")
if len(parts) != 3 {
t.Errorf("Expected 3 parts, got %d", len(parts))
}
if parts[0] != "testuser" {
t.Errorf("Expected username testuser, got %s", parts[0])
}
}Module Version: 1.0.0
Last Updated: February 2026
Status: Stable