CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-arweave

JavaScript/TypeScript client library for the Arweave decentralized permanent data storage network

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

encrypted-storage-silo.mddocs/

Encrypted Storage (Silo)

Silo protocol implementation for encrypted data storage with URI-based access control. Enables secure, encrypted data storage on Arweave with controlled access through cryptographic keys.

Capabilities

Create Silo Transaction

Create an encrypted transaction using the Silo protocol.

/**
 * Create encrypted Silo transaction
 * @param attributes - Transaction attributes (must include data)
 * @param jwk - Wallet key for signing
 * @param siloUri - Silo URI containing encryption parameters
 * @returns Promise resolving to encrypted Transaction
 */
createSiloTransaction(
  attributes: Partial<CreateTransactionInterface>,
  jwk: JWKInterface,
  siloUri: string
): Promise<Transaction>;

Usage Example:

import Arweave from "arweave";

const arweave = Arweave.init();
const key = await arweave.wallets.generate();

// Create Silo URI (in practice, this would come from a Silo provider)
const siloUri = "silo://access-key@encryption-key";

// Create encrypted transaction
const secretData = "This is confidential information";
const siloTransaction = await arweave.createSiloTransaction({
  data: secretData,
  tags: [
    { name: "Content-Type", value: "text/plain" },
    { name: "Encrypted", value: "true" }
  ]
}, key, siloUri);

await arweave.transactions.sign(siloTransaction, key);
await arweave.transactions.post(siloTransaction);

Retrieve Encrypted Data

Retrieve and decrypt data from a Silo URI.

/**
 * Retrieve and decrypt data from Silo URI
 * @param siloURI - Silo URI containing access and encryption keys
 * @returns Promise resolving to decrypted data
 */
get(siloURI: string): Promise<Uint8Array>;

Usage Example:

// Retrieve encrypted data using the same Silo URI
const siloUri = "silo://access-key@encryption-key";
const decryptedData = await arweave.silo.get(siloUri);

// Convert to string if it's text data
const textData = Arweave.utils.bufferToString(decryptedData);
console.log("Decrypted data:", textData);

Read Transaction Data

Decrypt Silo transaction data using the Silo URI.

/**
 * Decrypt Silo transaction data
 * @param transaction - Transaction containing encrypted Silo data
 * @param siloURI - Silo URI with decryption keys
 * @returns Promise resolving to decrypted data
 */
readTransactionData(transaction: Transaction, siloURI: string): Promise<Uint8Array>;

Usage Example:

// Get Silo transaction and decrypt its data
const transactionId = "silo-transaction-id";
const transaction = await arweave.transactions.get(transactionId);
const siloUri = "silo://access-key@encryption-key";

const decryptedData = await arweave.silo.readTransactionData(transaction, siloUri);
const textData = Arweave.utils.bufferToString(decryptedData);
console.log("Decrypted transaction data:", textData);

Parse Silo URI

Parse a Silo URI to extract access and encryption keys.

/**
 * Parse Silo URI into access keys
 * @param siloURI - Silo URI to parse
 * @returns Promise resolving to SiloResource
 */
parseUri(siloURI: string): Promise<SiloResource>;

Usage Example:

const siloUri = "silo://my-access-key@my-encryption-key";
const siloResource = await arweave.silo.parseUri(siloUri);

console.log("Access key:", siloResource.getAccessKey());
console.log("URI:", siloResource.getUri());
console.log("Encryption key length:", siloResource.getEncryptionKey().length);

SiloResource Class

Represents parsed Silo URI with access to encryption parameters.

Methods

class SiloResource {
  /**
   * Get the original Silo URI
   * @returns Silo URI string
   */
  getUri(): string;
  
  /**
   * Get the access key for Silo identification
   * @returns Access key string
   */
  getAccessKey(): string;
  
  /**
   * Get the encryption key for data encryption/decryption
   * @returns Encryption key as Uint8Array
   */
  getEncryptionKey(): Uint8Array;
}

Advanced Usage Examples

Secure Document Storage

// Store encrypted document with metadata
async function storeSecureDocument(
  document: string,
  metadata: { title: string; author: string; date: string },
  key: JWKInterface,
  siloUri: string
): Promise<string> {
  
  // Combine document and metadata
  const documentData = {
    content: document,
    metadata: metadata,
    timestamp: Date.now()
  };
  
  const jsonData = JSON.stringify(documentData);
  
  // Create encrypted Silo transaction
  const transaction = await arweave.createSiloTransaction({
    data: jsonData,
    tags: [
      { name: "Content-Type", value: "application/json" },
      { name: "Document-Type", value: "secure-document" },
      { name: "Author", value: metadata.author }
    ]
  }, key, siloUri);
  
  await arweave.transactions.sign(transaction, key);
  await arweave.transactions.post(transaction);
  
  return transaction.id;
}

// Usage
const key = await arweave.wallets.generate();
const siloUri = "silo://doc-access@doc-encryption-key";
const documentId = await storeSecureDocument(
  "This is a confidential document",
  { title: "Secret Report", author: "John Doe", date: "2024-01-01" },
  key,
  siloUri
);

Encrypted File Sharing

// Share encrypted file with specific access controls
async function shareEncryptedFile(
  fileData: Uint8Array,
  fileName: string,
  fileType: string,
  key: JWKInterface
): Promise<{ transactionId: string; siloUri: string }> {
  
  // Generate unique encryption keys for this file
  const accessKey = generateRandomString(32);
  const encryptionKey = generateRandomString(64);
  const siloUri = `silo://${accessKey}@${encryptionKey}`;
  
  // Create encrypted transaction
  const transaction = await arweave.createSiloTransaction({
    data: fileData,
    tags: [
      { name: "Content-Type", value: fileType },
      { name: "File-Name", value: fileName },
      { name: "Encrypted", value: "true" }
    ]
  }, key, siloUri);
  
  await arweave.transactions.sign(transaction, key);
  await arweave.transactions.post(transaction);
  
  return {
    transactionId: transaction.id,
    siloUri: siloUri
  };
}

// Retrieve shared encrypted file
async function retrieveSharedFile(siloUri: string): Promise<{
  data: Uint8Array;
  fileName: string;
  fileType: string;
}> {
  // Decrypt the data
  const decryptedData = await arweave.silo.get(siloUri);
  
  // Parse Silo URI to get access key
  const siloResource = await arweave.silo.parseUri(siloUri);
  const accessKey = siloResource.getAccessKey();
  
  // Find transaction by Silo access key
  // (In practice, you'd store the transaction ID with the Silo URI)
  
  return {
    data: decryptedData,
    fileName: "retrieved-file",
    fileType: "application/octet-stream"
  };
}

Multi-User Encrypted Storage

// Create Silo with multiple access keys for team sharing
class TeamSilo {
  private baseUri: string;
  private teamMembers: Map<string, string> = new Map();
  
  constructor(baseAccessKey: string, baseEncryptionKey: string) {
    this.baseUri = `silo://${baseAccessKey}@${baseEncryptionKey}`;
  }
  
  // Add team member with their own access key
  addMember(memberId: string, memberAccessKey: string) {
    this.teamMembers.set(memberId, memberAccessKey);
  }
  
  // Create Silo URI for specific member
  getSiloUri(memberId: string): string {
    const memberAccessKey = this.teamMembers.get(memberId);
    if (!memberAccessKey) {
      throw new Error(`Member ${memberId} not found`);
    }
    
    const siloResource = parseManualSiloUri(this.baseUri);
    return `silo://${memberAccessKey}@${siloResource.encryptionKey}`;
  }
  
  // Store data accessible to all team members
  async storeTeamData(
    data: string,
    key: JWKInterface,
    metadata: { type: string; title: string }
  ): Promise<string> {
    const transaction = await arweave.createSiloTransaction({
      data: data,
      tags: [
        { name: "Content-Type", value: "text/plain" },
        { name: "Team-Resource", value: "true" },
        { name: "Resource-Type", value: metadata.type },
        { name: "Title", value: metadata.title }
      ]
    }, key, this.baseUri);
    
    await arweave.transactions.sign(transaction, key);
    await arweave.transactions.post(transaction);
    
    return transaction.id;
  }
}

// Usage
const teamSilo = new TeamSilo("team-access-key", "team-encryption-key");
teamSilo.addMember("alice", "alice-access-key");
teamSilo.addMember("bob", "bob-access-key");

// Alice stores data
const aliceKey = await arweave.wallets.generate();
const dataId = await teamSilo.storeTeamData(
  "Team meeting notes",
  aliceKey,
  { type: "notes", title: "Weekly Standup" }
);

// Bob retrieves data using his access
const bobSiloUri = teamSilo.getSiloUri("bob");
const decryptedNotes = await arweave.silo.get(bobSiloUri);

Security Considerations

Key Management

// ✅ Good: Generate cryptographically secure keys
function generateSecureSiloKeys(): { accessKey: string; encryptionKey: string } {
  const accessKey = crypto.getRandomValues(new Uint8Array(32));
  const encryptionKey = crypto.getRandomValues(new Uint8Array(64));
  
  return {
    accessKey: Arweave.utils.bufferTob64Url(accessKey),
    encryptionKey: Arweave.utils.bufferTob64Url(encryptionKey)
  };
}

// ❌ Bad: Predictable or weak keys
const weakKeys = {
  accessKey: "simple-key",
  encryptionKey: "another-simple-key"
};

Access Control

// ✅ Good: Validate Silo URI format
function validateSiloUri(uri: string): boolean {
  const siloPattern = /^silo:\/\/[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+$/;
  return siloPattern.test(uri);
}

// ✅ Good: Implement access logging
async function auditedSiloAccess(siloUri: string): Promise<Uint8Array> {
  console.log(`Accessing Silo at ${Date.now()}: ${siloUri.substring(0, 20)}...`);
  
  try {
    const data = await arweave.silo.get(siloUri);
    console.log(`Successfully retrieved ${data.length} bytes`);
    return data;
  } catch (error) {
    console.error(`Failed to access Silo: ${error.message}`);
    throw error;
  }
}

Types

Silo URI Format

/** Silo URI format: silo://access-key@encryption-key */
type SiloUri = string;

Constants

/** Silo protocol version identifier */
const SILO_VERSION: string = "0.1.0";

/** Default Silo URI scheme */
const SILO_SCHEME: string = "silo://";

Helper Functions

// Utility functions for working with Silo URIs
function generateRandomString(length: number): string {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
  const randomBytes = crypto.getRandomValues(new Uint8Array(length));
  return Array.from(randomBytes)
    .map(byte => chars[byte % chars.length])
    .join('');
}

function parseManualSiloUri(uri: string): { accessKey: string; encryptionKey: string } {
  const match = uri.match(/^silo:\/\/([^@]+)@(.+)$/);
  if (!match) {
    throw new Error("Invalid Silo URI format");
  }
  
  return {
    accessKey: match[1],
    encryptionKey: match[2]
  };
}

docs

cryptographic-operations.md

currency-utilities.md

data-upload-chunking.md

data-utilities.md

encrypted-storage-silo.md

index.md

network-blockchain.md

transaction-management.md

wallet-operations.md

tile.json