Spaces:
Running
Running
File size: 13,029 Bytes
507acad |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
ο»Ώ# Storage Module (`modules/storage.py`) Usage Guide
The `storage.py` module provides helper functions for:
- Generating permalinks for 3D viewer projects.
- Uploading files in batches to a Hugging Face repository.
- Managing URL shortening by storing (short URL, full URL) pairs in a JSON file on the repository.
- Retrieving full URLs from short URL IDs and vice versa.
- Handle specific file types for 3D models, images, video and audio.
- **π Cryptographic key management for Open Badge 3.0 issuers.**
## Key Functions
### 1. `generate_permalink(valid_files, base_url_external, permalink_viewer_url="surn-3d-viewer.hf.space")`
- **Purpose:**
Given a list of file paths, it looks for exactly one model file (with an extension defined in `model_extensions`) and exactly two image files (extensions defined in `image_extensions`). If the criteria are met, it returns a permalink URL built from the base URL and query parameters.
- **Usage Example:**from modules.storage import generate_permalink
valid_files = [
"models/3d_model.glb",
"images/model_texture.png",
"images/model_depth.png"
]
base_url_external = "https://huggingface.co/datasets/Surn/Storage/resolve/main/saved_models/my_model"
permalink = generate_permalink(valid_files, base_url_external)
if permalink:
print("Permalink:", permalink)
### 2. `generate_permalink_from_urls(model_url, hm_url, img_url, permalink_viewer_url="surn-3d-viewer.hf.space")`
- **Purpose:**
Constructs a permalink URL by combining individual URLs for a 3D model (`model_url`), height map (`hm_url`), and image (`img_url`) into a single URL with corresponding query parameters.
- **Usage Example:**from modules.storage import generate_permalink_from_urls
model_url = "https://example.com/model.glb"
hm_url = "https://example.com/heightmap.png"
img_url = "https://example.com/source.png"
permalink = generate_permalink_from_urls(model_url, hm_url, img_url)
print("Generated Permalink:", permalink)
### 3. `upload_files_to_repo(files, repo_id, folder_name, create_permalink=False, repo_type="dataset", permalink_viewer_url="surn-3d-viewer.hf.space")`
- **Purpose:**
Uploads a batch of files (each file represented as a path string) to a specified Hugging Face repository (e.g. `"Surn/Storage"`) under a given folder.
The function's return type is `Union[Dict[str, Any], List[Tuple[Any, str]]]`.
- When `create_permalink` is `True` and exactly three valid files (one model and two images) are provided, the function returns a dictionary:{
"response": <upload_folder_response>,
"permalink": "<full_permalink_url>",
"short_permalink": "<shortened_permalink_url_with_sid>"
} - Otherwise (or if `create_permalink` is `False` or conditions for permalink creation are not met), it returns a list of tuples, where each tuple is `(upload_folder_response, individual_file_link)`.
- If no valid files are provided, it returns an empty list `[]` (this case should ideally also return the dictionary with empty/None values for consistency, but currently returns `[]` as per the code).
- **Usage Example:**
**a. Uploading with permalink creation:**from modules.storage import upload_files_to_repo
files_for_permalink = [
"local/path/to/model.glb",
"local/path/to/heightmap.png",
"local/path/to/image.png"
]
repo_id = "Surn/Storage" # Make sure this is defined, e.g., from constants or environment variables
folder_name = "my_new_model_with_permalink"
upload_result = upload_files_to_repo(
files_for_permalink,
repo_id,
folder_name,
create_permalink=True
)
if isinstance(upload_result, dict):
print("Upload Response:", upload_result.get("response"))
print("Full Permalink:", upload_result.get("permalink"))
print("Short Permalink:", upload_result.get("short_permalink"))
elif upload_result: # Check if list is not empty
print("Upload Response for individual files:")
for res, link in upload_result:
print(f" Response: {res}, Link: {link}")
else:
print("No files uploaded or error occurred.")
**b. Uploading without permalink creation (or if conditions for permalink are not met):**from modules.storage import upload_files_to_repo
files_individual = [
"local/path/to/another_model.obj",
"local/path/to/texture.jpg"
]
repo_id = "Surn/Storage"
folder_name = "my_other_uploads"
upload_results_list = upload_files_to_repo(
files_individual,
repo_id,
folder_name,
create_permalink=False # Or if create_permalink=True but not 1 model & 2 images
)
if upload_results_list: # Will be a list of tuples
print("Upload results for individual files:")
for res, link in upload_results_list:
print(f" Upload Response: {res}, File Link: {link}")
else:
print("No files uploaded or error occurred.")
### 4. URL Shortening Functions: `gen_full_url(...)` and Helpers
The module also enables URL shortening by managing a JSON file (e.g. `shortener.json`) in a Hugging Face repository. It supports CRUD-like operations:
- **Read:** Look up the full URL using a provided short URL ID.
- **Create:** Generate a new short URL ID for a full URL if no existing mapping exists.
- **Update/Conflict Handling:**
If both short URL ID and full URL are provided, it checks consistency and either confirms or reports a conflict.
#### `gen_full_url(short_url=None, full_url=None, repo_id=None, repo_type="dataset", permalink_viewer_url="surn-3d-viewer.hf.space", json_file="shortener.json")`
- **Purpose:**
Based on which parameter is provided, it retrieves or creates a mapping between a short URL ID and a full URL.
- If only `short_url` (the ID) is given, it returns the corresponding `full_url`.
- If only `full_url` is given, it looks up an existing `short_url` ID or generates and stores a new one.
- If both are given, it validates and returns the mapping or an error status.
- **Returns:** A tuple `(status_message, result_url)`, where `status_message` indicates the outcome (e.g., `"success_retrieved_full"`, `"created_short"`) and `result_url` is the relevant URL (full or short ID).
- **Usage Examples:**
**a. Convert a full URL into a short URL ID:**from modules.storage import gen_full_url
from modules.constants import HF_REPO_ID, SHORTENER_JSON_FILE # Assuming these are defined
full_permalink = "https://surn-3d-viewer.hf.space/?3d=https%3A%2F%2Fexample.com%2Fmodel.glb&hm=https%3A%2F%2Fexample.com%2Fheightmap.png&image=https%3A%2F%2Fexample.com%2Fsource.png"
status, short_id = gen_full_url(
full_url=full_permalink,
repo_id=HF_REPO_ID,
json_file=SHORTENER_JSON_FILE
)
print("Status:", status)
if status == "created_short" or status == "success_retrieved_short":
print("Shortened URL ID:", short_id)
# Construct the full short URL for sharing:
# permalink_viewer_url = "surn-3d-viewer.hf.space" # Or from constants
# shareable_short_url = f"https://{permalink_viewer_url}/?sid={short_id}"
# print("Shareable Short URL:", shareable_short_url)
**b. Retrieve the full URL from a short URL ID:**from modules.storage import gen_full_url
from modules.constants import HF_REPO_ID, SHORTENER_JSON_FILE # Assuming these are defined
short_id_to_lookup = "aBcDeFg1" # Example short URL ID
status, retrieved_full_url = gen_full_url(
short_url=short_id_to_lookup,
repo_id=HF_REPO_ID,
json_file=SHORTENER_JSON_FILE
)
print("Status:", status)
if status == "success_retrieved_full":
print("Retrieved Full URL:", retrieved_full_url)
## π Cryptographic Key Management Functions
### 5. `store_issuer_keypair(issuer_id, public_key, private_key, repo_id=None)`
- **Purpose:**
Securely store cryptographic keys for an issuer in a private Hugging Face repository. Private keys are encrypted before storage.
- **β οΈ IMPORTANT:** This function requires a PRIVATE Hugging Face repository to ensure the security of stored private keys. Never use this with public repositories.
- **Storage Structure:**keys/issuers/{issuer_id}/
βββ private_key.json (encrypted)
βββ public_key.json- **Returns:** `bool` - True if keys were stored successfully, False otherwise.
- **Usage Example:**from modules.storage import store_issuer_keypair
# Example Ed25519 keys (multibase encoded)
issuer_id = "https://example.edu/issuers/565049"
public_key = "z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
private_key = "z3u2MQhLnQw7nvJRGJCdKdqfXHV4N7BLKuEGFWnJqsVSdgYv"
success = store_issuer_keypair(issuer_id, public_key, private_key)
if success:
print("Keys stored successfully")
else:
print("Failed to store keys")
### 6. `get_issuer_keypair(issuer_id, repo_id=None)`
- **Purpose:**
Retrieve and decrypt stored cryptographic keys for an issuer from the private Hugging Face repository.
- **β οΈ IMPORTANT:** This function accesses a PRIVATE Hugging Face repository containing encrypted private keys. Ensure proper access control and security measures.
- **Returns:** `Tuple[Optional[str], Optional[str]]` - (public_key, private_key) or (None, None) if not found.
- **Usage Example:**from modules.storage import get_issuer_keypair
issuer_id = "https://example.edu/issuers/565049"
public_key, private_key = get_issuer_keypair(issuer_id)
if public_key and private_key:
print("Keys retrieved successfully")
print(f"Public key: {public_key}")
# Use private_key for signing operations
else:
print("Keys not found or error occurred")
### 7. `get_verification_methods_registry(repo_id=None)`
- **Purpose:**
Retrieve the global verification methods registry containing all registered issuer public keys.
- **Returns:** `Dict[str, Any]` - Registry data containing all verification methods.
- **Usage Example:**from modules.storage import get_verification_methods_registry
registry = get_verification_methods_registry()
methods = registry.get("verification_methods", [])
for method in methods:
print(f"Issuer: {method['issuer_id']}")
print(f"Public Key: {method['public_key']}")
print(f"Key Type: {method['key_type']}")
print("---")
### 8. `list_issuer_ids(repo_id=None)`
- **Purpose:**
List all issuer IDs that have stored keys in the repository.
- **Returns:** `List[str]` - List of issuer IDs.
- **Usage Example:**from modules.storage import list_issuer_ids
issuer_ids = list_issuer_ids()
print("Registered issuers:")
for issuer_id in issuer_ids:
print(f" - {issuer_id}")
## Notes
- **Authentication:** All functions that interact with Hugging Face Hub use the HF API token defined as `HF_API_TOKEN` in `modules/constants.py`. Ensure this environment variable is correctly set.
- **Constants:** Functions like `gen_full_url` and `upload_files_to_repo` (when creating short links) rely on `HF_REPO_ID` and `SHORTENER_JSON_FILE` from `modules/constants.py` for the URL shortening feature.
- **π Private Repository Requirement:** Key management functions require a PRIVATE Hugging Face repository to ensure the security of stored encrypted private keys. Never use these functions with public repositories.
- **File Types:** Only files with extensions included in `upload_file_types` (a combination of `model_extensions` and `image_extensions` from `modules/constants.py`) are processed by `upload_files_to_repo`.
- **Repository Configuration:** When using URL shortening, file uploads, and key management, ensure that the specified Hugging Face repository (e.g., defined by `HF_REPO_ID`) exists and that you have write permissions.
- **Temporary Directory:** `upload_files_to_repo` temporarily copies files to a local directory (configured by `TMPDIR` in `modules/constants.py`) before uploading.
- **Key Encryption:** Private keys are encrypted using basic XOR encryption (demo implementation). In production environments, upgrade to proper encryption like Fernet from the cryptography library.
- **Error Handling:** Functions include basic error handling (e.g., catching `RepositoryNotFoundError`, `EntryNotFoundError`, JSON decoding errors, or upload issues) and print messages to the console for debugging. Review function return values to handle these cases appropriately in your application.
## π Security Considerations for Key Management
1. **Private Repository Only:** Always use private repositories for key storage to protect cryptographic material.
2. **Key Sanitization:** Issuer IDs are sanitized for file system compatibility (replacing special characters with underscores).
3. **Encryption:** Private keys are encrypted before storage. Upgrade to Fernet encryption in production.
4. **Access Control:** Implement proper authentication and authorization for key access.
5. **Key Rotation:** Consider implementing key rotation mechanisms for enhanced security.
6. **Audit Logging:** Monitor key access and usage patterns for security auditing.
---
This guide provides the essential usage examples for interacting with the storage, URL-shortening, and cryptographic key management functionality. You can integrate these examples into your application or use them as a reference when extending functionality.
|