* clear

* feat: Add everything

* fix: Commenht
This commit is contained in:
Prad Nukala
2025-10-03 14:45:52 -04:00
committed by GitHub
parent 43b4a11c06
commit 13e6c3e84d
1935 changed files with 655061 additions and 40058 deletions
-1
View File
@@ -1 +0,0 @@
package types
Regular → Executable
+13 -3
View File
@@ -9,8 +9,9 @@ import (
)
var (
amino = codec.NewLegacyAmino()
AminoCdc = codec.NewAminoCodec(amino)
amino = codec.NewLegacyAmino()
AminoCdc = codec.NewAminoCodec(amino)
ModuleCdc = codec.NewProtoCodec(types.NewInterfaceRegistry())
)
func init() {
@@ -22,13 +23,22 @@ func init() {
// RegisterLegacyAminoCodec registers concrete types on the LegacyAmino codec
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&MsgUpdateParams{}, ModuleName+"/MsgUpdateParams", nil)
cdc.RegisterConcrete(&MsgRecordsWrite{}, ModuleName+"/MsgRecordsWrite", nil)
cdc.RegisterConcrete(&MsgRecordsDelete{}, ModuleName+"/MsgRecordsDelete", nil)
cdc.RegisterConcrete(&MsgProtocolsConfigure{}, ModuleName+"/MsgProtocolsConfigure", nil)
cdc.RegisterConcrete(&MsgPermissionsGrant{}, ModuleName+"/MsgPermissionsGrant", nil)
cdc.RegisterConcrete(&MsgPermissionsRevoke{}, ModuleName+"/MsgPermissionsRevoke", nil)
}
func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations(
(*sdk.Msg)(nil),
&MsgUpdateParams{},
&MsgRecordsWrite{},
&MsgRecordsDelete{},
&MsgProtocolsConfigure{},
&MsgPermissionsGrant{},
&MsgPermissionsRevoke{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
+113
View File
@@ -0,0 +1,113 @@
package types
import (
apiv1 "github.com/sonr-io/sonr/api/dwn/v1"
)
// ConvertAPIRecordToType converts from API DWNRecord to types.DWNRecord
func ConvertAPIRecordToType(record *apiv1.DWNRecord) DWNRecord {
typeRecord := DWNRecord{
RecordId: record.RecordId,
Target: record.Target,
Authorization: record.Authorization,
Data: record.Data,
Protocol: record.Protocol,
ProtocolPath: record.ProtocolPath,
Schema: record.Schema,
ParentId: record.ParentId,
Published: record.Published,
Attestation: record.Attestation,
Encryption: record.Encryption,
KeyDerivationScheme: record.KeyDerivationScheme,
CreatedAt: record.CreatedAt,
UpdatedAt: record.UpdatedAt,
CreatedHeight: record.CreatedHeight,
}
// Convert descriptor
if record.Descriptor_ != nil {
typeRecord.Descriptor_ = &DWNMessageDescriptor{
InterfaceName: record.Descriptor_.InterfaceName,
Method: record.Descriptor_.Method,
MessageTimestamp: record.Descriptor_.MessageTimestamp,
DataCid: record.Descriptor_.DataCid,
DataSize: record.Descriptor_.DataSize,
DataFormat: record.Descriptor_.DataFormat,
}
}
return typeRecord
}
// ConvertAPIProtocolToType converts from API DWNProtocol to types.DWNProtocol
func ConvertAPIProtocolToType(protocol *apiv1.DWNProtocol) DWNProtocol {
return DWNProtocol{
Target: protocol.Target,
ProtocolUri: protocol.ProtocolUri,
Definition: protocol.Definition,
Published: protocol.Published,
CreatedAt: protocol.CreatedAt,
CreatedHeight: protocol.CreatedHeight,
}
}
// ConvertAPIPermissionToType converts from API DWNPermission to types.DWNPermission
func ConvertAPIPermissionToType(permission *apiv1.DWNPermission) DWNPermission {
return DWNPermission{
PermissionId: permission.PermissionId,
Grantor: permission.Grantor,
Grantee: permission.Grantee,
Target: permission.Target,
InterfaceName: permission.InterfaceName,
Method: permission.Method,
Protocol: permission.Protocol,
RecordId: permission.RecordId,
Conditions: permission.Conditions,
ExpiresAt: permission.ExpiresAt,
CreatedAt: permission.CreatedAt,
Revoked: permission.Revoked,
CreatedHeight: permission.CreatedHeight,
}
}
// ConvertAPIVaultToType converts from API VaultState to types.VaultState
func ConvertAPIVaultToType(vault *apiv1.VaultState) VaultState {
typeVault := VaultState{
VaultId: vault.VaultId,
Owner: vault.Owner,
PublicKey: vault.PublicKey,
CreatedAt: vault.CreatedAt,
LastRefreshed: vault.LastRefreshed,
CreatedHeight: vault.CreatedHeight,
}
// Convert enclave data
if vault.EnclaveData != nil {
typeVault.EnclaveData = &EnclaveData{
PrivateData: vault.EnclaveData.PrivateData,
PublicKey: vault.EnclaveData.PublicKey,
EnclaveId: vault.EnclaveData.EnclaveId,
Version: vault.EnclaveData.Version,
}
}
return typeVault
}
// ConvertAPIEncryptionMetadataToType converts from API EncryptionMetadata to types.EncryptionMetadata
func ConvertAPIEncryptionMetadataToType(metadata *apiv1.EncryptionMetadata) *EncryptionMetadata {
if metadata == nil {
return nil
}
return &EncryptionMetadata{
Algorithm: metadata.Algorithm,
ConsensusInput: metadata.ConsensusInput,
Nonce: metadata.Nonce,
AuthTag: metadata.AuthTag,
EncryptionHeight: metadata.EncryptionHeight,
ValidatorSet: metadata.ValidatorSet,
KeyVersion: metadata.KeyVersion,
SingleNodeMode: metadata.SingleNodeMode,
}
}
+185
View File
@@ -0,0 +1,185 @@
package types
import (
apiv1 "github.com/sonr-io/sonr/api/dwn/v1"
)
// ToAPIEncryptionMetadata converts types.EncryptionMetadata to apiv1.EncryptionMetadata
func (em *EncryptionMetadata) ToAPIEncryptionMetadata() *apiv1.EncryptionMetadata {
if em == nil {
return nil
}
return &apiv1.EncryptionMetadata{
Algorithm: em.Algorithm,
ConsensusInput: em.ConsensusInput,
Nonce: em.Nonce,
AuthTag: em.AuthTag,
EncryptionHeight: em.EncryptionHeight,
ValidatorSet: em.ValidatorSet,
KeyVersion: em.KeyVersion,
SingleNodeMode: em.SingleNodeMode,
}
}
// FromAPIEncryptionMetadata converts apiv1.EncryptionMetadata to types.EncryptionMetadata
func FromAPIEncryptionMetadata(apiMeta *apiv1.EncryptionMetadata) *EncryptionMetadata {
if apiMeta == nil {
return nil
}
return &EncryptionMetadata{
Algorithm: apiMeta.Algorithm,
ConsensusInput: apiMeta.ConsensusInput,
Nonce: apiMeta.Nonce,
AuthTag: apiMeta.AuthTag,
EncryptionHeight: apiMeta.EncryptionHeight,
ValidatorSet: apiMeta.ValidatorSet,
KeyVersion: apiMeta.KeyVersion,
SingleNodeMode: apiMeta.SingleNodeMode,
}
}
// ToAPIVRFContribution converts types.VRFContribution to apiv1.VRFContribution
func (vrf *VRFContribution) ToAPIVRFContribution() *apiv1.VRFContribution {
if vrf == nil {
return nil
}
return &apiv1.VRFContribution{
ValidatorAddress: vrf.ValidatorAddress,
Randomness: vrf.Randomness,
Proof: vrf.Proof,
BlockHeight: vrf.BlockHeight,
Timestamp: vrf.Timestamp,
}
}
// FromAPIVRFContribution converts apiv1.VRFContribution to types.VRFContribution
func FromAPIVRFContribution(apiVrf *apiv1.VRFContribution) *VRFContribution {
if apiVrf == nil {
return nil
}
return &VRFContribution{
ValidatorAddress: apiVrf.ValidatorAddress,
Randomness: apiVrf.Randomness,
Proof: apiVrf.Proof,
BlockHeight: apiVrf.BlockHeight,
Timestamp: apiVrf.Timestamp,
}
}
// ToAPIEncryptionKeyState converts types.EncryptionKeyState to apiv1.EncryptionKeyState
func (eks *EncryptionKeyState) ToAPIEncryptionKeyState() *apiv1.EncryptionKeyState {
if eks == nil {
return nil
}
// Convert contribution slice to API format
apiContributions := make([]*apiv1.VRFContribution, len(eks.Contributions))
for i, contrib := range eks.Contributions {
if contrib != nil {
apiContributions[i] = contrib.ToAPIVRFContribution()
}
}
return &apiv1.EncryptionKeyState{
CurrentKey: eks.CurrentKey,
KeyVersion: eks.KeyVersion,
ValidatorSet: eks.ValidatorSet,
Contributions: apiContributions,
LastRotation: eks.LastRotation,
NextRotation: eks.NextRotation,
SingleNodeMode: eks.SingleNodeMode,
}
}
// FromAPIEncryptionKeyState converts apiv1.EncryptionKeyState to types.EncryptionKeyState
func FromAPIEncryptionKeyState(apiEks *apiv1.EncryptionKeyState) *EncryptionKeyState {
if apiEks == nil {
return nil
}
// Convert API contribution slice to types format
contributions := make([]*VRFContribution, len(apiEks.Contributions))
for i, apiContrib := range apiEks.Contributions {
if apiContrib != nil {
contributions[i] = FromAPIVRFContribution(apiContrib)
}
}
return &EncryptionKeyState{
CurrentKey: apiEks.CurrentKey,
KeyVersion: apiEks.KeyVersion,
ValidatorSet: apiEks.ValidatorSet,
Contributions: contributions,
LastRotation: apiEks.LastRotation,
NextRotation: apiEks.NextRotation,
SingleNodeMode: apiEks.SingleNodeMode,
}
}
// ToAPIVRFConsensusRound converts types.VRFConsensusRound to apiv1.VRFConsensusRound
func (vcr *VRFConsensusRound) ToAPIVRFConsensusRound() *apiv1.VRFConsensusRound {
if vcr == nil {
return nil
}
return &apiv1.VRFConsensusRound{
RoundNumber: vcr.RoundNumber,
KeyVersion: vcr.KeyVersion,
RequiredContributions: vcr.RequiredContributions,
ReceivedContributions: vcr.ReceivedContributions,
Status: vcr.Status,
ExpiryHeight: vcr.ExpiryHeight,
InitiatedHeight: vcr.InitiatedHeight,
ConsensusInput: vcr.ConsensusInput,
Completed: vcr.Completed,
}
}
// FromAPIVRFConsensusRound converts apiv1.VRFConsensusRound to types.VRFConsensusRound
func FromAPIVRFConsensusRound(apiVcr *apiv1.VRFConsensusRound) *VRFConsensusRound {
if apiVcr == nil {
return nil
}
return &VRFConsensusRound{
RoundNumber: apiVcr.RoundNumber,
KeyVersion: apiVcr.KeyVersion,
RequiredContributions: apiVcr.RequiredContributions,
ReceivedContributions: apiVcr.ReceivedContributions,
Status: apiVcr.Status,
ExpiryHeight: apiVcr.ExpiryHeight,
InitiatedHeight: apiVcr.InitiatedHeight,
ConsensusInput: apiVcr.ConsensusInput,
Completed: apiVcr.Completed,
}
}
// ToAPIEncryptionStats converts types.EncryptionStats to apiv1.EncryptionStats
func (es *EncryptionStats) ToAPIEncryptionStats() *apiv1.EncryptionStats {
if es == nil {
return nil
}
return &apiv1.EncryptionStats{
TotalEncryptedRecords: es.TotalEncryptedRecords,
TotalDecryptionErrors: es.TotalDecryptionErrors,
LastEncryptionHeight: es.LastEncryptionHeight,
}
}
// FromAPIEncryptionStats converts apiv1.EncryptionStats to types.EncryptionStats
func FromAPIEncryptionStats(apiEs *apiv1.EncryptionStats) *EncryptionStats {
if apiEs == nil {
return nil
}
return &EncryptionStats{
TotalEncryptedRecords: apiEs.TotalEncryptedRecords,
TotalDecryptionErrors: apiEs.TotalDecryptionErrors,
LastEncryptionHeight: apiEs.LastEncryptionHeight,
}
}
-48
View File
@@ -1,48 +0,0 @@
package embed
import (
"encoding/json"
"github.com/ipfs/boxo/files"
motr "github.com/onsonr/motr/pkg/config"
)
const SchemaVersion = 1
const (
AppManifestFileName = "app.webmanifest"
DWNConfigFileName = "dwn.json"
IndexHTMLFileName = "index.html"
MainJSFileName = "main.js"
ServiceWorkerFileName = "sw.js"
)
// spawnVaultDirectory creates a new directory with the default files
func NewVaultFS(cfg *motr.Config) (files.Directory, error) {
manifestBz, err := NewWebManifest()
if err != nil {
return nil, err
}
cnfBz, err := json.Marshal(cfg)
if err != nil {
return nil, err
}
return files.NewMapDirectory(map[string]files.Node{
AppManifestFileName: files.NewBytesFile(manifestBz),
DWNConfigFileName: files.NewBytesFile(cnfBz),
IndexHTMLFileName: files.NewBytesFile(IndexHTML),
MainJSFileName: files.NewBytesFile(MainJS),
ServiceWorkerFileName: files.NewBytesFile(WorkerJS),
}), nil
}
// NewVaultConfig returns the default vault config
func NewVaultConfig(addr string, ucanCID string) *motr.Config {
return &motr.Config{
MotrToken: ucanCID,
MotrAddress: addr,
IpfsGatewayUrl: "http://localhost:80",
SonrApiUrl: "http://localhost:1317",
SonrRpcUrl: "http://localhost:26657",
SonrChainId: "sonr-testnet-1",
}
}
-138
View File
@@ -1,138 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sonr DWN</title>
<!-- HTMX -->
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<!-- WASM Support -->
<script src="https://cdn.jsdelivr.net/gh/golang/go@go1.22.5/misc/wasm/wasm_exec.js"></script>
<!-- Main JS -->
<script src="main.js"></script>
<!-- Tailwind (assuming you're using it based on your classes) -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Add manifest for PWA support -->
<link
rel="manifest"
href="/app.webmanifest"
crossorigin="use-credentials"
/>
<!-- Offline detection styles -->
<style>
.offline-indicator {
display: none;
}
body.offline .offline-indicator {
display: block;
background: #f44336;
color: white;
text-align: center;
padding: 0.5rem;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
}
</style>
</head>
<body
class="flex items-center justify-center h-full bg-zinc-50 lg:p-24 md:16 p-4"
>
<!-- Offline indicator -->
<div class="offline-indicator">
You are currently offline. Some features may be limited.
</div>
<!-- Loading indicator -->
<div
id="loading-indicator"
class="fixed top-0 left-0 w-full h-1 bg-blue-200 transition-all duration-300"
style="display: none"
>
<div class="h-full bg-blue-600 w-0 transition-all duration-300"></div>
</div>
<main
class="flex-row items-center justify-center mx-auto w-fit max-w-screen-sm gap-y-3"
>
<div
id="content"
hx-get="/#"
hx-trigger="load"
hx-swap="outerHTML"
hx-indicator="#loading-indicator"
>
Loading...
</div>
</main>
<!-- WASM Ready Indicator (hidden) -->
<div
id="wasm-status"
class="hidden fixed bottom-4 right-4 p-2 rounded-md bg-green-500 text-white"
hx-swap-oob="true"
>
WASM Ready
</div>
<script>
// Initialize service worker
if ("serviceWorker" in navigator) {
window.addEventListener("load", async function () {
try {
const registration =
await navigator.serviceWorker.register("/sw.js");
console.log(
"Service Worker registered with scope:",
registration.scope,
);
} catch (error) {
console.error("Service Worker registration failed:", error);
}
});
}
// HTMX loading indicator
htmx.on("htmx:beforeRequest", function (evt) {
document.getElementById("loading-indicator").style.display = "block";
});
htmx.on("htmx:afterRequest", function (evt) {
document.getElementById("loading-indicator").style.display = "none";
});
// WASM ready event handler
document.addEventListener("wasm-ready", function () {
const status = document.getElementById("wasm-status");
status.classList.remove("hidden");
setTimeout(() => {
status.classList.add("hidden");
}, 3000);
});
// Offline status handler
window.addEventListener("offline", function () {
document.body.classList.add("offline");
});
window.addEventListener("online", function () {
document.body.classList.remove("offline");
});
// Initial offline check
if (!navigator.onLine) {
document.body.classList.add("offline");
}
</script>
</body>
</html>
-158
View File
@@ -1,158 +0,0 @@
// MessageChannel for WASM communication
let wasmChannel;
let wasmPort;
async function initWasmChannel() {
wasmChannel = new MessageChannel();
wasmPort = wasmChannel.port1;
// Setup message handling from WASM
wasmPort.onmessage = (event) => {
const { type, data } = event.data;
switch (type) {
case "WASM_READY":
console.log("WASM is ready");
document.dispatchEvent(new CustomEvent("wasm-ready"));
break;
case "RESPONSE":
handleWasmResponse(data);
break;
case "SYNC_COMPLETE":
handleSyncComplete(data);
break;
}
};
}
// Initialize WebAssembly and Service Worker
async function init() {
try {
// Register service worker
if ("serviceWorker" in navigator) {
const registration = await navigator.serviceWorker.register("./sw.js");
console.log("ServiceWorker registered");
// Wait for the service worker to be ready
await navigator.serviceWorker.ready;
// Initialize MessageChannel
await initWasmChannel();
// Send the MessageChannel port to the service worker
navigator.serviceWorker.controller.postMessage(
{
type: "PORT_INITIALIZATION",
port: wasmChannel.port2,
},
[wasmChannel.port2],
);
// Register for periodic sync if available
if ("periodicSync" in registration) {
try {
await registration.periodicSync.register("wasm-sync", {
minInterval: 24 * 60 * 60 * 1000, // 24 hours
});
} catch (error) {
console.log("Periodic sync could not be registered:", error);
}
}
}
// Initialize HTMX with custom config
htmx.config.withCredentials = true;
htmx.config.wsReconnectDelay = "full-jitter";
// Override HTMX's internal request handling
htmx.config.beforeRequest = function (config) {
// Add request ID for tracking
const requestId = "req_" + Date.now();
config.headers["X-Wasm-Request-ID"] = requestId;
// If offline, handle through service worker
if (!navigator.onLine) {
return false; // Let service worker handle it
}
return true;
};
// Handle HTMX after request
htmx.config.afterRequest = function (config) {
// Additional processing after request if needed
};
// Handle HTMX errors
htmx.config.errorHandler = function (error) {
console.error("HTMX Error:", error);
};
} catch (error) {
console.error("Initialization failed:", error);
}
}
function handleWasmResponse(data) {
const { requestId, response } = data;
// Process the WASM response
// This might update the UI or trigger HTMX swaps
const targetElement = document.querySelector(
`[data-request-id="${requestId}"]`,
);
if (targetElement) {
htmx.process(targetElement);
}
}
function handleSyncComplete(data) {
const { url } = data;
// Handle successful sync
// Maybe refresh the relevant part of the UI
htmx.trigger("body", "sync:complete", { url });
}
// Handle offline status changes
window.addEventListener("online", () => {
document.body.classList.remove("offline");
// Trigger sync when back online
if (wasmPort) {
wasmPort.postMessage({ type: "SYNC_REQUEST" });
}
});
window.addEventListener("offline", () => {
document.body.classList.add("offline");
});
// Custom event handlers for HTMX
document.addEventListener("htmx:beforeRequest", (event) => {
const { elt, xhr } = event.detail;
// Add request tracking
const requestId = xhr.headers["X-Wasm-Request-ID"];
elt.setAttribute("data-request-id", requestId);
});
document.addEventListener("htmx:afterRequest", (event) => {
const { elt, successful } = event.detail;
if (successful) {
elt.removeAttribute("data-request-id");
}
});
// Initialize everything when the page loads
document.addEventListener("DOMContentLoaded", init);
// Export functions that might be needed by WASM
window.wasmBridge = {
triggerUIUpdate: function (selector, content) {
const target = document.querySelector(selector);
if (target) {
htmx.process(
htmx.parse(content).forEach((node) => target.appendChild(node)),
);
}
},
showNotification: function (message, type = "info") {
// Implement notification system
console.log(`${type}: ${message}`);
},
};
-257
View File
@@ -1,257 +0,0 @@
// Cache names for different types of resources
const CACHE_NAMES = {
wasm: "wasm-cache-v1",
static: "static-cache-v1",
dynamic: "dynamic-cache-v1",
};
// Import required scripts
importScripts(
"https://cdn.jsdelivr.net/gh/golang/go@go1.22.5/misc/wasm/wasm_exec.js",
"https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.1.0/sw.js",
);
// Initialize WASM HTTP listener
const wasmInstance = registerWasmHTTPListener(
"https://cdn.sonr.id/wasm/app.wasm",
);
// MessageChannel port for WASM communication
let wasmPort;
// Request queue for offline operations
let requestQueue = new Map();
// Setup message channel handler
self.addEventListener("message", async (event) => {
if (event.data.type === "PORT_INITIALIZATION") {
wasmPort = event.data.port;
setupWasmCommunication();
}
});
function setupWasmCommunication() {
wasmPort.onmessage = async (event) => {
const { type, data } = event.data;
switch (type) {
case "WASM_REQUEST":
handleWasmRequest(data);
break;
case "SYNC_REQUEST":
processSyncQueue();
break;
}
};
// Notify that WASM is ready
wasmPort.postMessage({ type: "WASM_READY" });
}
// Enhanced install event
self.addEventListener("install", (event) => {
event.waitUntil(
Promise.all([
skipWaiting(),
// Cache WASM binary and essential resources
caches
.open(CACHE_NAMES.wasm)
.then((cache) =>
cache.addAll([
"https://cdn.sonr.id/wasm/app.wasm",
"https://cdn.jsdelivr.net/gh/golang/go@go1.22.5/misc/wasm/wasm_exec.js",
]),
),
]),
);
});
// Enhanced activate event
self.addEventListener("activate", (event) => {
event.waitUntil(
Promise.all([
clients.claim(),
// Clean up old caches
caches.keys().then((keys) =>
Promise.all(
keys.map((key) => {
if (!Object.values(CACHE_NAMES).includes(key)) {
return caches.delete(key);
}
}),
),
),
]),
);
});
// Intercept fetch events
self.addEventListener("fetch", (event) => {
const request = event.request;
// Handle API requests differently from static resources
if (request.url.includes("/api/")) {
event.respondWith(handleApiRequest(request));
} else {
event.respondWith(handleStaticRequest(request));
}
});
async function handleApiRequest(request) {
try {
// Try to make the request
const response = await fetch(request.clone());
// If successful, pass through WASM handler
if (response.ok) {
return await processWasmResponse(request, response);
}
// If offline or failed, queue the request
await queueRequest(request);
// Return cached response if available
const cachedResponse = await caches.match(request);
if (cachedResponse) {
return cachedResponse;
}
// Return offline response
return new Response(JSON.stringify({ error: "Currently offline" }), {
status: 503,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
await queueRequest(request);
return new Response(JSON.stringify({ error: "Request failed" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
async function handleStaticRequest(request) {
// Check cache first
const cachedResponse = await caches.match(request);
if (cachedResponse) {
return cachedResponse;
}
try {
const response = await fetch(request);
// Cache successful responses
if (response.ok) {
const cache = await caches.open(CACHE_NAMES.static);
cache.put(request, response.clone());
}
return response;
} catch (error) {
// Return offline page for navigation requests
if (request.mode === "navigate") {
return caches.match("/offline.html");
}
throw error;
}
}
async function processWasmResponse(request, response) {
// Clone the response before processing
const responseClone = response.clone();
try {
// Process through WASM
const processedResponse = await wasmInstance.processResponse(responseClone);
// Notify client through message channel
if (wasmPort) {
wasmPort.postMessage({
type: "RESPONSE",
requestId: request.headers.get("X-Wasm-Request-ID"),
response: processedResponse,
});
}
return processedResponse;
} catch (error) {
console.error("WASM processing error:", error);
return response;
}
}
async function queueRequest(request) {
const serializedRequest = await serializeRequest(request);
requestQueue.set(request.url, serializedRequest);
// Register for background sync
try {
await self.registration.sync.register("wasm-sync");
} catch (error) {
console.error("Sync registration failed:", error);
}
}
async function serializeRequest(request) {
const headers = {};
for (const [key, value] of request.headers.entries()) {
headers[key] = value;
}
return {
url: request.url,
method: request.method,
headers,
body: await request.text(),
timestamp: Date.now(),
};
}
// Handle background sync
self.addEventListener("sync", (event) => {
if (event.tag === "wasm-sync") {
event.waitUntil(processSyncQueue());
}
});
async function processSyncQueue() {
const requests = Array.from(requestQueue.values());
for (const serializedRequest of requests) {
try {
const response = await fetch(
new Request(serializedRequest.url, {
method: serializedRequest.method,
headers: serializedRequest.headers,
body: serializedRequest.body,
}),
);
if (response.ok) {
requestQueue.delete(serializedRequest.url);
// Notify client of successful sync
if (wasmPort) {
wasmPort.postMessage({
type: "SYNC_COMPLETE",
url: serializedRequest.url,
});
}
}
} catch (error) {
console.error("Sync failed for request:", error);
}
}
}
// Handle payment requests
self.addEventListener("canmakepayment", function (e) {
e.respondWith(Promise.resolve(true));
});
// Handle periodic sync if available
self.addEventListener("periodicsync", (event) => {
if (event.tag === "wasm-sync") {
event.waitUntil(processSyncQueue());
}
});
-47
View File
@@ -1,47 +0,0 @@
package embed
import (
_ "embed"
"reflect"
"strings"
)
//go:embed index.html
var IndexHTML []byte
//go:embed main.js
var MainJS []byte
//go:embed sw.js
var WorkerJS []byte
func getSchema(structType interface{}) string {
t := reflect.TypeOf(structType)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return ""
}
var fields []string
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fieldName := toCamelCase(field.Name)
fields = append(fields, fieldName)
}
// Add "++" at the beginning, separated by a comma
return "++, " + strings.Join(fields, ", ")
}
func toCamelCase(s string) string {
if s == "" {
return s
}
if len(s) == 1 {
return strings.ToLower(s)
}
return strings.ToLower(s[:1]) + s[1:]
}
-124
View File
@@ -1,124 +0,0 @@
package embed
import "encoding/json"
func NewWebManifest() ([]byte, error) {
return json.Marshal(baseWebManifest)
}
var baseWebManifest = WebManifest{
Name: "Sonr Vault",
ShortName: "Sonr.ID",
StartURL: "/index.html",
Display: "standalone",
DisplayOverride: []string{
"fullscreen",
"minimal-ui",
},
Icons: []IconDefinition{
{
Src: "/icons/icon-192x192.png",
Sizes: "192x192",
Type: "image/png",
},
},
ServiceWorker: ServiceWorker{
Scope: "/",
Src: "/sw.js",
UseCache: true,
},
ProtocolHandlers: []ProtocolHandler{
{
Scheme: "did.sonr",
URL: "/resolve/sonr/%s",
},
{
Scheme: "did.eth",
URL: "/resolve/eth/%s",
},
{
Scheme: "did.btc",
URL: "/resolve/btc/%s",
},
{
Scheme: "did.usdc",
URL: "/resolve/usdc/%s",
},
{
Scheme: "did.ipfs",
URL: "/resolve/ipfs/%s",
},
},
}
type WebManifest struct {
// Required fields
Name string `json:"name"` // Full name of the application
ShortName string `json:"short_name"` // Short version of the name
// Display and appearance
Description string `json:"description,omitempty"` // Purpose and features of the application
Display string `json:"display,omitempty"` // Preferred display mode: fullscreen, standalone, minimal-ui, browser
DisplayOverride []string `json:"display_override,omitempty"`
ThemeColor string `json:"theme_color,omitempty"` // Default theme color for the application
BackgroundColor string `json:"background_color,omitempty"` // Background color during launch
Orientation string `json:"orientation,omitempty"` // Default orientation: any, natural, landscape, portrait
// URLs and scope
StartURL string `json:"start_url"` // Starting URL when launching
Scope string `json:"scope,omitempty"` // Navigation scope of the web application
ServiceWorker ServiceWorker `json:"service_worker,omitempty"`
// Icons
Icons []IconDefinition `json:"icons,omitempty"`
// Optional features
RelatedApplications []RelatedApplication `json:"related_applications,omitempty"`
PreferRelatedApplications bool `json:"prefer_related_applications,omitempty"`
Shortcuts []Shortcut `json:"shortcuts,omitempty"`
// Experimental features (uncomment if needed)
FileHandlers []FileHandler `json:"file_handlers,omitempty"`
ProtocolHandlers []ProtocolHandler `json:"protocol_handlers,omitempty"`
}
type FileHandler struct {
Action string `json:"action"`
Accept map[string][]string `json:"accept"`
}
type LaunchHandler struct {
Action string `json:"action"`
}
type IconDefinition struct {
Src string `json:"src"`
Sizes string `json:"sizes"`
Type string `json:"type,omitempty"`
Purpose string `json:"purpose,omitempty"`
}
type ProtocolHandler struct {
Scheme string `json:"scheme"`
URL string `json:"url"`
}
type RelatedApplication struct {
Platform string `json:"platform"`
URL string `json:"url,omitempty"`
ID string `json:"id,omitempty"`
}
type Shortcut struct {
Name string `json:"name"`
ShortName string `json:"short_name,omitempty"`
Description string `json:"description,omitempty"`
URL string `json:"url"`
Icons []IconDefinition `json:"icons,omitempty"`
}
type ServiceWorker struct {
Scope string `json:"scope"`
Src string `json:"src"`
UseCache bool `json:"use_cache"`
}
+175
View File
@@ -0,0 +1,175 @@
package types
import (
"cosmossdk.io/errors"
)
// DWN module sentinel errors
var (
// Request validation errors (1-15)
ErrInvalidRequest = errors.Register(ModuleName, 1, "invalid request")
ErrRequestCannotBeNil = errors.Register(ModuleName, 2, "request cannot be nil")
ErrTargetDIDEmpty = errors.Register(ModuleName, 3, "target DID cannot be empty")
ErrRecordIDEmpty = errors.Register(ModuleName, 4, "record ID cannot be empty")
ErrProtocolURIEmpty = errors.Register(ModuleName, 5, "protocol URI cannot be empty")
ErrVaultIDEmpty = errors.Register(ModuleName, 6, "vault ID cannot be empty")
ErrPermissionIDEmpty = errors.Register(ModuleName, 7, "permission ID cannot be empty")
ErrPublicKeyEmpty = errors.Register(ModuleName, 8, "public key cannot be empty")
ErrMessageEmpty = errors.Register(ModuleName, 9, "message cannot be empty")
ErrSignatureEmpty = errors.Register(ModuleName, 10, "signature cannot be empty")
ErrDIDEmpty = errors.Register(ModuleName, 11, "DID cannot be empty")
ErrSaltEmpty = errors.Register(ModuleName, 12, "salt cannot be empty")
ErrAddressEmpty = errors.Register(ModuleName, 13, "address cannot be empty")
ErrInvalidAddressFormat = errors.Register(ModuleName, 14, "invalid address format")
ErrInvalidAuthorityFormat = errors.Register(ModuleName, 15, "invalid authority format")
// Record management errors (16-25)
ErrRecordNotFound = errors.Register(ModuleName, 16, "record not found")
ErrRecordSizeExceeded = errors.Register(ModuleName, 17, "record size exceeds maximum allowed")
ErrRecordAlreadyExists = errors.Register(ModuleName, 18, "record already exists")
ErrRecordDataInvalid = errors.Register(ModuleName, 19, "record data is invalid")
ErrRecordSchemaInvalid = errors.Register(ModuleName, 20, "record schema is invalid")
ErrRecordEncrypted = errors.Register(ModuleName, 21, "record is encrypted")
ErrRecordDecryption = errors.Register(ModuleName, 22, "failed to decrypt record")
ErrRecordEncryption = errors.Register(ModuleName, 23, "failed to encrypt record")
ErrRecordSignature = errors.Register(ModuleName, 24, "invalid record signature")
ErrRecordPermission = errors.Register(ModuleName, 25, "insufficient permissions for record")
// Protocol management errors (26-35)
ErrProtocolNotFound = errors.Register(ModuleName, 26, "protocol not found")
ErrProtocolAlreadyExists = errors.Register(ModuleName, 27, "protocol already exists")
ErrProtocolLimitReached = errors.Register(ModuleName, 28, "protocol limit reached for DWN")
ErrProtocolInvalid = errors.Register(ModuleName, 29, "protocol definition is invalid")
ErrProtocolPermission = errors.Register(
ModuleName,
30,
"insufficient permissions for protocol",
)
ErrProtocolVersionInvalid = errors.Register(ModuleName, 31, "protocol version is invalid")
ErrProtocolURIInvalid = errors.Register(ModuleName, 32, "protocol URI is invalid")
ErrProtocolConfigInvalid = errors.Register(ModuleName, 33, "protocol configuration is invalid")
ErrProtocolRuleInvalid = errors.Register(ModuleName, 34, "protocol rule is invalid")
ErrProtocolActionInvalid = errors.Register(ModuleName, 35, "protocol action is invalid")
// Permission management errors (36-46)
ErrPermissionNotFound = errors.Register(ModuleName, 36, "permission not found")
ErrPermissionAlreadyExists = errors.Register(ModuleName, 37, "permission already exists")
ErrPermissionLimitReached = errors.Register(
ModuleName,
38,
"permission limit reached for DWN",
)
ErrPermissionAlreadyRevoked = errors.Register(ModuleName, 39, "permission already revoked")
ErrPermissionInvalid = errors.Register(ModuleName, 40, "permission is invalid")
ErrPermissionExpired = errors.Register(ModuleName, 41, "permission has expired")
ErrPermissionScope = errors.Register(ModuleName, 42, "permission scope is invalid")
ErrPermissionGrantInvalid = errors.Register(ModuleName, 43, "permission grant is invalid")
ErrPermissionDenied = errors.Register(ModuleName, 44, "permission denied")
ErrPermissionInherited = errors.Register(
ModuleName,
45,
"cannot modify inherited permission",
)
ErrInvalidUCANToken = errors.Register(
ModuleName,
46,
"UCAN token is invalid or insufficient",
)
// Vault management errors (47-56)
ErrVaultNotFound = errors.Register(ModuleName, 47, "vault not found")
ErrVaultAlreadyExists = errors.Register(ModuleName, 48, "vault already exists")
ErrVaultNotInitialized = errors.Register(ModuleName, 49, "vault not initialized")
ErrVaultInitializationFailed = errors.Register(ModuleName, 50, "vault initialization failed")
ErrVaultOperationFailed = errors.Register(ModuleName, 51, "vault operation failed")
ErrVaultPermission = errors.Register(ModuleName, 52, "insufficient vault permissions")
ErrVaultKeyNotFound = errors.Register(ModuleName, 53, "vault key not found")
ErrVaultKeyInvalid = errors.Register(ModuleName, 54, "vault key is invalid")
ErrVaultSecretInvalid = errors.Register(ModuleName, 55, "vault secret is invalid")
ErrVaultLocked = errors.Register(ModuleName, 56, "vault is locked")
// Wallet derivation errors (57-68)
ErrWalletDerivationFailed = errors.Register(
ModuleName,
57,
"failed to derive wallet addresses",
)
ErrWalletCreateFailed = errors.Register(ModuleName, 58, "failed to create wallet")
ErrWalletSignFailed = errors.Register(ModuleName, 59, "failed to sign message")
ErrWalletVerifyFailed = errors.Register(ModuleName, 60, "failed to verify signature")
ErrWalletAddressMismatch = errors.Register(ModuleName, 61, "wallet address mismatch")
ErrWalletKeyInvalid = errors.Register(ModuleName, 62, "wallet key is invalid")
ErrWalletSeedInvalid = errors.Register(ModuleName, 63, "wallet seed is invalid")
ErrWalletPathInvalid = errors.Register(
ModuleName,
64,
"wallet derivation path is invalid",
)
ErrWalletTypeUnsupported = errors.Register(ModuleName, 65, "wallet type is unsupported")
ErrWalletNotFound = errors.Register(ModuleName, 66, "wallet not found")
ErrUnsupportedTransactionType = errors.Register(ModuleName, 67, "unsupported transaction type")
ErrWalletOperationFailed = errors.Register(ModuleName, 68, "wallet operation failed")
// Cryptographic errors (69-78)
ErrCryptographicOperation = errors.Register(ModuleName, 69, "cryptographic operation failed")
ErrSignatureVerification = errors.Register(ModuleName, 70, "signature verification failed")
ErrKeyGeneration = errors.Register(ModuleName, 71, "key generation failed")
ErrHashGeneration = errors.Register(ModuleName, 72, "hash generation failed")
ErrEncryptionFailed = errors.Register(ModuleName, 73, "encryption failed")
ErrDecryptionFailed = errors.Register(ModuleName, 74, "decryption failed")
ErrKeyExchange = errors.Register(ModuleName, 75, "key exchange failed")
ErrKeyDerivation = errors.Register(ModuleName, 76, "key derivation failed")
ErrCertificateInvalid = errors.Register(ModuleName, 77, "certificate is invalid")
ErrCertificateExpired = errors.Register(ModuleName, 78, "certificate has expired")
// Storage and state errors (79-88)
ErrStorageOperation = errors.Register(ModuleName, 79, "storage operation failed")
ErrStateCorrupted = errors.Register(ModuleName, 80, "state is corrupted")
ErrStateMismatch = errors.Register(ModuleName, 81, "state mismatch")
ErrStateNotFound = errors.Register(ModuleName, 82, "state not found")
ErrStateInvalid = errors.Register(ModuleName, 83, "state is invalid")
ErrStateConflict = errors.Register(ModuleName, 84, "state conflict")
ErrStateLocked = errors.Register(ModuleName, 85, "state is locked")
ErrStateExpired = errors.Register(ModuleName, 86, "state has expired")
ErrStatePermission = errors.Register(ModuleName, 87, "insufficient state permissions")
ErrStateVersion = errors.Register(ModuleName, 88, "state version mismatch")
// Network and communication errors (89-98)
ErrNetworkOperation = errors.Register(ModuleName, 89, "network operation failed")
ErrConnectionFailed = errors.Register(ModuleName, 90, "connection failed")
ErrTimeoutExceeded = errors.Register(ModuleName, 91, "timeout exceeded")
ErrRateLimitExceeded = errors.Register(ModuleName, 92, "rate limit exceeded")
ErrQuotaExceeded = errors.Register(ModuleName, 93, "quota exceeded")
ErrResourceExhausted = errors.Register(ModuleName, 94, "resource exhausted")
ErrServiceUnavailable = errors.Register(ModuleName, 95, "service unavailable")
ErrServiceTimeout = errors.Register(ModuleName, 96, "service timeout")
ErrServiceError = errors.Register(ModuleName, 97, "service error")
ErrServiceMaintenance = errors.Register(ModuleName, 98, "service under maintenance")
// Generic operation errors (99-102)
ErrNotImplemented = errors.Register(ModuleName, 99, "operation not implemented")
ErrOperationFailed = errors.Register(ModuleName, 100, "operation failed")
ErrInternalError = errors.Register(ModuleName, 101, "internal error")
ErrUnknownError = errors.Register(ModuleName, 102, "unknown error")
// Service verification errors (103-104)
ErrServiceNotVerified = errors.Register(ModuleName, 103, "service not verified for domain")
ErrUnauthorized = errors.Register(ModuleName, 104, "unauthorized access")
// Fee grant and wallet sponsorship errors (105-115)
ErrInvalidWalletAddress = errors.Register(ModuleName, 105, "invalid wallet address")
ErrInvalidSpendLimit = errors.Register(ModuleName, 106, "invalid spend limit")
ErrFeeGrantNotFound = errors.Register(ModuleName, 107, "fee grant not found")
ErrFeeGrantAlreadyExists = errors.Register(ModuleName, 108, "fee grant already exists")
ErrWalletNotSponsorable = errors.Register(ModuleName, 109, "wallet is not sponsorable")
ErrSelfGrantNotAllowed = errors.Register(ModuleName, 110, "self grants are not allowed")
ErrDailyLimitExceeded = errors.Register(ModuleName, 111, "daily limit exceeded")
ErrMessageTypeNotAllowed = errors.Register(ModuleName, 112, "message type not allowed")
ErrSponsorshipExpired = errors.Register(ModuleName, 113, "sponsorship has expired")
ErrInsufficientSponsorBalance = errors.Register(ModuleName, 114, "insufficient sponsor balance")
ErrGasEstimationFailed = errors.Register(ModuleName, 115, "gas estimation failed")
ErrFeeGrantExhausted = errors.Register(ModuleName, 116, "fee grant has been exhausted")
// IPFS errors (117-126)
ErrIPFSClientNotAvailable = errors.Register(ModuleName, 117, "IPFS client not available")
)
+391
View File
@@ -0,0 +1,391 @@
package types_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/sonr-io/sonr/x/dwn/types"
)
func TestErrorDefinitions(t *testing.T) {
// Test that all errors are properly defined
require.NotNil(t, types.ErrInvalidRequest)
require.NotNil(t, types.ErrRequestCannotBeNil)
require.NotNil(t, types.ErrTargetDIDEmpty)
require.NotNil(t, types.ErrRecordIDEmpty)
require.NotNil(t, types.ErrProtocolURIEmpty)
require.NotNil(t, types.ErrVaultIDEmpty)
require.NotNil(t, types.ErrPermissionIDEmpty)
require.NotNil(t, types.ErrPublicKeyEmpty)
require.NotNil(t, types.ErrMessageEmpty)
require.NotNil(t, types.ErrSignatureEmpty)
require.NotNil(t, types.ErrDIDEmpty)
require.NotNil(t, types.ErrSaltEmpty)
require.NotNil(t, types.ErrAddressEmpty)
require.NotNil(t, types.ErrInvalidAddressFormat)
require.NotNil(t, types.ErrInvalidAuthorityFormat)
// Record management errors
require.NotNil(t, types.ErrRecordNotFound)
require.NotNil(t, types.ErrRecordSizeExceeded)
require.NotNil(t, types.ErrRecordAlreadyExists)
require.NotNil(t, types.ErrRecordDataInvalid)
require.NotNil(t, types.ErrRecordSchemaInvalid)
require.NotNil(t, types.ErrRecordEncrypted)
require.NotNil(t, types.ErrRecordDecryption)
require.NotNil(t, types.ErrRecordEncryption)
require.NotNil(t, types.ErrRecordSignature)
require.NotNil(t, types.ErrRecordPermission)
// Protocol management errors
require.NotNil(t, types.ErrProtocolNotFound)
require.NotNil(t, types.ErrProtocolAlreadyExists)
require.NotNil(t, types.ErrProtocolLimitReached)
require.NotNil(t, types.ErrProtocolInvalid)
require.NotNil(t, types.ErrProtocolPermission)
require.NotNil(t, types.ErrProtocolVersionInvalid)
require.NotNil(t, types.ErrProtocolURIInvalid)
require.NotNil(t, types.ErrProtocolConfigInvalid)
require.NotNil(t, types.ErrProtocolRuleInvalid)
require.NotNil(t, types.ErrProtocolActionInvalid)
// Permission management errors
require.NotNil(t, types.ErrPermissionNotFound)
require.NotNil(t, types.ErrPermissionAlreadyExists)
require.NotNil(t, types.ErrPermissionLimitReached)
require.NotNil(t, types.ErrPermissionAlreadyRevoked)
require.NotNil(t, types.ErrPermissionInvalid)
require.NotNil(t, types.ErrPermissionExpired)
require.NotNil(t, types.ErrPermissionScope)
require.NotNil(t, types.ErrPermissionGrantInvalid)
require.NotNil(t, types.ErrPermissionDenied)
require.NotNil(t, types.ErrPermissionInherited)
require.NotNil(t, types.ErrInvalidUCANToken)
// Vault management errors
require.NotNil(t, types.ErrVaultNotFound)
require.NotNil(t, types.ErrVaultAlreadyExists)
require.NotNil(t, types.ErrVaultNotInitialized)
require.NotNil(t, types.ErrVaultInitializationFailed)
require.NotNil(t, types.ErrVaultOperationFailed)
require.NotNil(t, types.ErrVaultPermission)
require.NotNil(t, types.ErrVaultKeyNotFound)
require.NotNil(t, types.ErrVaultKeyInvalid)
require.NotNil(t, types.ErrVaultSecretInvalid)
require.NotNil(t, types.ErrVaultLocked)
// Wallet derivation errors
require.NotNil(t, types.ErrWalletDerivationFailed)
require.NotNil(t, types.ErrWalletCreateFailed)
require.NotNil(t, types.ErrWalletSignFailed)
require.NotNil(t, types.ErrWalletVerifyFailed)
require.NotNil(t, types.ErrWalletAddressMismatch)
require.NotNil(t, types.ErrWalletKeyInvalid)
require.NotNil(t, types.ErrWalletSeedInvalid)
require.NotNil(t, types.ErrWalletPathInvalid)
require.NotNil(t, types.ErrWalletTypeUnsupported)
require.NotNil(t, types.ErrWalletNotFound)
// Cryptographic errors
require.NotNil(t, types.ErrCryptographicOperation)
require.NotNil(t, types.ErrSignatureVerification)
require.NotNil(t, types.ErrKeyGeneration)
require.NotNil(t, types.ErrHashGeneration)
require.NotNil(t, types.ErrEncryptionFailed)
require.NotNil(t, types.ErrDecryptionFailed)
require.NotNil(t, types.ErrKeyExchange)
require.NotNil(t, types.ErrKeyDerivation)
require.NotNil(t, types.ErrCertificateInvalid)
require.NotNil(t, types.ErrCertificateExpired)
// Storage and state errors
require.NotNil(t, types.ErrStorageOperation)
require.NotNil(t, types.ErrStateCorrupted)
require.NotNil(t, types.ErrStateMismatch)
require.NotNil(t, types.ErrStateNotFound)
require.NotNil(t, types.ErrStateInvalid)
require.NotNil(t, types.ErrStateConflict)
require.NotNil(t, types.ErrStateLocked)
require.NotNil(t, types.ErrStateExpired)
require.NotNil(t, types.ErrStatePermission)
require.NotNil(t, types.ErrStateVersion)
// Network and communication errors
require.NotNil(t, types.ErrNetworkOperation)
require.NotNil(t, types.ErrConnectionFailed)
require.NotNil(t, types.ErrTimeoutExceeded)
require.NotNil(t, types.ErrRateLimitExceeded)
require.NotNil(t, types.ErrQuotaExceeded)
require.NotNil(t, types.ErrResourceExhausted)
require.NotNil(t, types.ErrServiceUnavailable)
require.NotNil(t, types.ErrServiceTimeout)
require.NotNil(t, types.ErrServiceError)
require.NotNil(t, types.ErrServiceMaintenance)
// Generic operation errors
require.NotNil(t, types.ErrNotImplemented)
require.NotNil(t, types.ErrOperationFailed)
require.NotNil(t, types.ErrInternalError)
require.NotNil(t, types.ErrUnknownError)
// Service verification errors
require.NotNil(t, types.ErrServiceNotVerified)
}
func TestErrorMessages(t *testing.T) {
// Test that error messages are correct
require.Contains(t, types.ErrInvalidRequest.Error(), "invalid request")
require.Contains(t, types.ErrRequestCannotBeNil.Error(), "request cannot be nil")
require.Contains(t, types.ErrTargetDIDEmpty.Error(), "target DID cannot be empty")
require.Contains(t, types.ErrRecordIDEmpty.Error(), "record ID cannot be empty")
require.Contains(t, types.ErrProtocolURIEmpty.Error(), "protocol URI cannot be empty")
require.Contains(t, types.ErrVaultIDEmpty.Error(), "vault ID cannot be empty")
require.Contains(t, types.ErrPermissionIDEmpty.Error(), "permission ID cannot be empty")
require.Contains(t, types.ErrPublicKeyEmpty.Error(), "public key cannot be empty")
require.Contains(t, types.ErrMessageEmpty.Error(), "message cannot be empty")
require.Contains(t, types.ErrSignatureEmpty.Error(), "signature cannot be empty")
require.Contains(t, types.ErrDIDEmpty.Error(), "DID cannot be empty")
require.Contains(t, types.ErrSaltEmpty.Error(), "salt cannot be empty")
require.Contains(t, types.ErrAddressEmpty.Error(), "address cannot be empty")
require.Contains(t, types.ErrInvalidAddressFormat.Error(), "invalid address format")
require.Contains(t, types.ErrInvalidAuthorityFormat.Error(), "invalid authority format")
// Record management error messages
require.Contains(t, types.ErrRecordNotFound.Error(), "record not found")
require.Contains(t, types.ErrRecordSizeExceeded.Error(), "record size exceeds maximum allowed")
require.Contains(t, types.ErrRecordAlreadyExists.Error(), "record already exists")
require.Contains(t, types.ErrRecordDataInvalid.Error(), "record data is invalid")
require.Contains(t, types.ErrRecordSchemaInvalid.Error(), "record schema is invalid")
require.Contains(t, types.ErrRecordEncrypted.Error(), "record is encrypted")
require.Contains(t, types.ErrRecordDecryption.Error(), "failed to decrypt record")
require.Contains(t, types.ErrRecordEncryption.Error(), "failed to encrypt record")
require.Contains(t, types.ErrRecordSignature.Error(), "invalid record signature")
require.Contains(t, types.ErrRecordPermission.Error(), "insufficient permissions for record")
// Protocol management error messages
require.Contains(t, types.ErrProtocolNotFound.Error(), "protocol not found")
require.Contains(t, types.ErrProtocolAlreadyExists.Error(), "protocol already exists")
require.Contains(t, types.ErrProtocolLimitReached.Error(), "protocol limit reached for DWN")
require.Contains(t, types.ErrProtocolInvalid.Error(), "protocol definition is invalid")
require.Contains(
t,
types.ErrProtocolPermission.Error(),
"insufficient permissions for protocol",
)
// Permission management error messages
require.Contains(t, types.ErrPermissionNotFound.Error(), "permission not found")
require.Contains(t, types.ErrPermissionAlreadyExists.Error(), "permission already exists")
require.Contains(t, types.ErrPermissionLimitReached.Error(), "permission limit reached for DWN")
require.Contains(t, types.ErrPermissionAlreadyRevoked.Error(), "permission already revoked")
require.Contains(t, types.ErrPermissionInvalid.Error(), "permission is invalid")
require.Contains(t, types.ErrPermissionExpired.Error(), "permission has expired")
require.Contains(t, types.ErrPermissionScope.Error(), "permission scope is invalid")
require.Contains(t, types.ErrPermissionGrantInvalid.Error(), "permission grant is invalid")
require.Contains(t, types.ErrPermissionDenied.Error(), "permission denied")
require.Contains(t, types.ErrPermissionInherited.Error(), "cannot modify inherited permission")
require.Contains(t, types.ErrInvalidUCANToken.Error(), "UCAN token is invalid or insufficient")
// Vault management error messages
require.Contains(t, types.ErrVaultNotFound.Error(), "vault not found")
require.Contains(t, types.ErrVaultAlreadyExists.Error(), "vault already exists")
require.Contains(t, types.ErrVaultNotInitialized.Error(), "vault not initialized")
require.Contains(t, types.ErrVaultInitializationFailed.Error(), "vault initialization failed")
require.Contains(t, types.ErrVaultOperationFailed.Error(), "vault operation failed")
require.Contains(t, types.ErrVaultPermission.Error(), "insufficient vault permissions")
require.Contains(t, types.ErrVaultKeyNotFound.Error(), "vault key not found")
require.Contains(t, types.ErrVaultKeyInvalid.Error(), "vault key is invalid")
require.Contains(t, types.ErrVaultSecretInvalid.Error(), "vault secret is invalid")
require.Contains(t, types.ErrVaultLocked.Error(), "vault is locked")
// Wallet derivation error messages
require.Contains(
t,
types.ErrWalletDerivationFailed.Error(),
"failed to derive wallet addresses",
)
require.Contains(t, types.ErrWalletCreateFailed.Error(), "failed to create wallet")
require.Contains(t, types.ErrWalletSignFailed.Error(), "failed to sign message")
require.Contains(t, types.ErrWalletVerifyFailed.Error(), "failed to verify signature")
require.Contains(t, types.ErrWalletAddressMismatch.Error(), "wallet address mismatch")
require.Contains(t, types.ErrWalletKeyInvalid.Error(), "wallet key is invalid")
require.Contains(t, types.ErrWalletSeedInvalid.Error(), "wallet seed is invalid")
require.Contains(t, types.ErrWalletPathInvalid.Error(), "wallet derivation path is invalid")
require.Contains(t, types.ErrWalletTypeUnsupported.Error(), "wallet type is unsupported")
require.Contains(t, types.ErrWalletNotFound.Error(), "wallet not found")
// Cryptographic error messages
require.Contains(t, types.ErrCryptographicOperation.Error(), "cryptographic operation failed")
require.Contains(t, types.ErrSignatureVerification.Error(), "signature verification failed")
require.Contains(t, types.ErrKeyGeneration.Error(), "key generation failed")
require.Contains(t, types.ErrHashGeneration.Error(), "hash generation failed")
require.Contains(t, types.ErrEncryptionFailed.Error(), "encryption failed")
require.Contains(t, types.ErrDecryptionFailed.Error(), "decryption failed")
require.Contains(t, types.ErrKeyExchange.Error(), "key exchange failed")
require.Contains(t, types.ErrKeyDerivation.Error(), "key derivation failed")
require.Contains(t, types.ErrCertificateInvalid.Error(), "certificate is invalid")
require.Contains(t, types.ErrCertificateExpired.Error(), "certificate has expired")
// Storage and state error messages
require.Contains(t, types.ErrStorageOperation.Error(), "storage operation failed")
require.Contains(t, types.ErrStateCorrupted.Error(), "state is corrupted")
require.Contains(t, types.ErrStateMismatch.Error(), "state mismatch")
require.Contains(t, types.ErrStateNotFound.Error(), "state not found")
require.Contains(t, types.ErrStateInvalid.Error(), "state is invalid")
require.Contains(t, types.ErrStateConflict.Error(), "state conflict")
require.Contains(t, types.ErrStateLocked.Error(), "state is locked")
require.Contains(t, types.ErrStateExpired.Error(), "state has expired")
require.Contains(t, types.ErrStatePermission.Error(), "insufficient state permissions")
require.Contains(t, types.ErrStateVersion.Error(), "state version mismatch")
// Network and communication error messages
require.Contains(t, types.ErrNetworkOperation.Error(), "network operation failed")
require.Contains(t, types.ErrConnectionFailed.Error(), "connection failed")
require.Contains(t, types.ErrTimeoutExceeded.Error(), "timeout exceeded")
require.Contains(t, types.ErrRateLimitExceeded.Error(), "rate limit exceeded")
require.Contains(t, types.ErrQuotaExceeded.Error(), "quota exceeded")
require.Contains(t, types.ErrResourceExhausted.Error(), "resource exhausted")
require.Contains(t, types.ErrServiceUnavailable.Error(), "service unavailable")
require.Contains(t, types.ErrServiceTimeout.Error(), "service timeout")
require.Contains(t, types.ErrServiceError.Error(), "service error")
require.Contains(t, types.ErrServiceMaintenance.Error(), "service under maintenance")
// Generic operation error messages
require.Contains(t, types.ErrNotImplemented.Error(), "operation not implemented")
require.Contains(t, types.ErrOperationFailed.Error(), "operation failed")
require.Contains(t, types.ErrInternalError.Error(), "internal error")
require.Contains(t, types.ErrUnknownError.Error(), "unknown error")
// Service verification error messages
require.Contains(t, types.ErrServiceNotVerified.Error(), "service not verified for domain")
}
func TestErrorCodes(t *testing.T) {
// Test that error codes are in the expected ranges
// Request validation errors (1-15)
require.Equal(t, uint32(1), types.ErrInvalidRequest.ABCICode())
require.Equal(t, uint32(2), types.ErrRequestCannotBeNil.ABCICode())
require.Equal(t, uint32(3), types.ErrTargetDIDEmpty.ABCICode())
require.Equal(t, uint32(4), types.ErrRecordIDEmpty.ABCICode())
require.Equal(t, uint32(5), types.ErrProtocolURIEmpty.ABCICode())
require.Equal(t, uint32(6), types.ErrVaultIDEmpty.ABCICode())
require.Equal(t, uint32(7), types.ErrPermissionIDEmpty.ABCICode())
require.Equal(t, uint32(8), types.ErrPublicKeyEmpty.ABCICode())
require.Equal(t, uint32(9), types.ErrMessageEmpty.ABCICode())
require.Equal(t, uint32(10), types.ErrSignatureEmpty.ABCICode())
require.Equal(t, uint32(11), types.ErrDIDEmpty.ABCICode())
require.Equal(t, uint32(12), types.ErrSaltEmpty.ABCICode())
require.Equal(t, uint32(13), types.ErrAddressEmpty.ABCICode())
require.Equal(t, uint32(14), types.ErrInvalidAddressFormat.ABCICode())
require.Equal(t, uint32(15), types.ErrInvalidAuthorityFormat.ABCICode())
// Record management errors (16-25)
require.Equal(t, uint32(16), types.ErrRecordNotFound.ABCICode())
require.Equal(t, uint32(17), types.ErrRecordSizeExceeded.ABCICode())
require.Equal(t, uint32(18), types.ErrRecordAlreadyExists.ABCICode())
require.Equal(t, uint32(19), types.ErrRecordDataInvalid.ABCICode())
require.Equal(t, uint32(20), types.ErrRecordSchemaInvalid.ABCICode())
require.Equal(t, uint32(21), types.ErrRecordEncrypted.ABCICode())
require.Equal(t, uint32(22), types.ErrRecordDecryption.ABCICode())
require.Equal(t, uint32(23), types.ErrRecordEncryption.ABCICode())
require.Equal(t, uint32(24), types.ErrRecordSignature.ABCICode())
require.Equal(t, uint32(25), types.ErrRecordPermission.ABCICode())
// Protocol management errors (26-35)
require.Equal(t, uint32(26), types.ErrProtocolNotFound.ABCICode())
require.Equal(t, uint32(27), types.ErrProtocolAlreadyExists.ABCICode())
require.Equal(t, uint32(28), types.ErrProtocolLimitReached.ABCICode())
require.Equal(t, uint32(29), types.ErrProtocolInvalid.ABCICode())
require.Equal(t, uint32(30), types.ErrProtocolPermission.ABCICode())
require.Equal(t, uint32(31), types.ErrProtocolVersionInvalid.ABCICode())
require.Equal(t, uint32(32), types.ErrProtocolURIInvalid.ABCICode())
require.Equal(t, uint32(33), types.ErrProtocolConfigInvalid.ABCICode())
require.Equal(t, uint32(34), types.ErrProtocolRuleInvalid.ABCICode())
require.Equal(t, uint32(35), types.ErrProtocolActionInvalid.ABCICode())
// Permission management errors (36-45)
require.Equal(t, uint32(36), types.ErrPermissionNotFound.ABCICode())
require.Equal(t, uint32(37), types.ErrPermissionAlreadyExists.ABCICode())
require.Equal(t, uint32(38), types.ErrPermissionLimitReached.ABCICode())
require.Equal(t, uint32(39), types.ErrPermissionAlreadyRevoked.ABCICode())
require.Equal(t, uint32(40), types.ErrPermissionInvalid.ABCICode())
require.Equal(t, uint32(41), types.ErrPermissionExpired.ABCICode())
require.Equal(t, uint32(42), types.ErrPermissionScope.ABCICode())
require.Equal(t, uint32(43), types.ErrPermissionGrantInvalid.ABCICode())
require.Equal(t, uint32(44), types.ErrPermissionDenied.ABCICode())
require.Equal(t, uint32(45), types.ErrPermissionInherited.ABCICode())
require.Equal(t, uint32(46), types.ErrInvalidUCANToken.ABCICode())
// Vault management errors (47-56)
require.Equal(t, uint32(47), types.ErrVaultNotFound.ABCICode())
require.Equal(t, uint32(48), types.ErrVaultAlreadyExists.ABCICode())
require.Equal(t, uint32(49), types.ErrVaultNotInitialized.ABCICode())
require.Equal(t, uint32(50), types.ErrVaultInitializationFailed.ABCICode())
require.Equal(t, uint32(51), types.ErrVaultOperationFailed.ABCICode())
require.Equal(t, uint32(52), types.ErrVaultPermission.ABCICode())
require.Equal(t, uint32(53), types.ErrVaultKeyNotFound.ABCICode())
require.Equal(t, uint32(54), types.ErrVaultKeyInvalid.ABCICode())
require.Equal(t, uint32(55), types.ErrVaultSecretInvalid.ABCICode())
require.Equal(t, uint32(56), types.ErrVaultLocked.ABCICode())
// Wallet derivation errors (57-66)
require.Equal(t, uint32(57), types.ErrWalletDerivationFailed.ABCICode())
require.Equal(t, uint32(58), types.ErrWalletCreateFailed.ABCICode())
require.Equal(t, uint32(59), types.ErrWalletSignFailed.ABCICode())
require.Equal(t, uint32(60), types.ErrWalletVerifyFailed.ABCICode())
require.Equal(t, uint32(61), types.ErrWalletAddressMismatch.ABCICode())
require.Equal(t, uint32(62), types.ErrWalletKeyInvalid.ABCICode())
require.Equal(t, uint32(63), types.ErrWalletSeedInvalid.ABCICode())
require.Equal(t, uint32(64), types.ErrWalletPathInvalid.ABCICode())
require.Equal(t, uint32(65), types.ErrWalletTypeUnsupported.ABCICode())
require.Equal(t, uint32(66), types.ErrWalletNotFound.ABCICode())
require.Equal(t, uint32(67), types.ErrUnsupportedTransactionType.ABCICode())
require.Equal(t, uint32(68), types.ErrWalletOperationFailed.ABCICode())
// Cryptographic errors (69-78)
require.Equal(t, uint32(69), types.ErrCryptographicOperation.ABCICode())
require.Equal(t, uint32(70), types.ErrSignatureVerification.ABCICode())
require.Equal(t, uint32(71), types.ErrKeyGeneration.ABCICode())
require.Equal(t, uint32(72), types.ErrHashGeneration.ABCICode())
require.Equal(t, uint32(73), types.ErrEncryptionFailed.ABCICode())
require.Equal(t, uint32(74), types.ErrDecryptionFailed.ABCICode())
require.Equal(t, uint32(75), types.ErrKeyExchange.ABCICode())
require.Equal(t, uint32(76), types.ErrKeyDerivation.ABCICode())
require.Equal(t, uint32(77), types.ErrCertificateInvalid.ABCICode())
require.Equal(t, uint32(78), types.ErrCertificateExpired.ABCICode())
// Storage and state errors (79-88)
require.Equal(t, uint32(79), types.ErrStorageOperation.ABCICode())
require.Equal(t, uint32(80), types.ErrStateCorrupted.ABCICode())
require.Equal(t, uint32(81), types.ErrStateMismatch.ABCICode())
require.Equal(t, uint32(82), types.ErrStateNotFound.ABCICode())
require.Equal(t, uint32(83), types.ErrStateInvalid.ABCICode())
require.Equal(t, uint32(84), types.ErrStateConflict.ABCICode())
require.Equal(t, uint32(85), types.ErrStateLocked.ABCICode())
require.Equal(t, uint32(86), types.ErrStateExpired.ABCICode())
require.Equal(t, uint32(87), types.ErrStatePermission.ABCICode())
require.Equal(t, uint32(88), types.ErrStateVersion.ABCICode())
// Network and communication errors (89-98)
require.Equal(t, uint32(89), types.ErrNetworkOperation.ABCICode())
require.Equal(t, uint32(90), types.ErrConnectionFailed.ABCICode())
require.Equal(t, uint32(91), types.ErrTimeoutExceeded.ABCICode())
require.Equal(t, uint32(92), types.ErrRateLimitExceeded.ABCICode())
require.Equal(t, uint32(93), types.ErrQuotaExceeded.ABCICode())
require.Equal(t, uint32(94), types.ErrResourceExhausted.ABCICode())
require.Equal(t, uint32(95), types.ErrServiceUnavailable.ABCICode())
require.Equal(t, uint32(96), types.ErrServiceTimeout.ABCICode())
require.Equal(t, uint32(97), types.ErrServiceError.ABCICode())
require.Equal(t, uint32(98), types.ErrServiceMaintenance.ABCICode())
// Generic operation errors (99-102)
require.Equal(t, uint32(99), types.ErrNotImplemented.ABCICode())
require.Equal(t, uint32(100), types.ErrOperationFailed.ABCICode())
require.Equal(t, uint32(101), types.ErrInternalError.ABCICode())
require.Equal(t, uint32(102), types.ErrUnknownError.ABCICode())
// Service verification errors (103)
require.Equal(t, uint32(103), types.ErrServiceNotVerified.ABCICode())
}
File diff suppressed because it is too large Load Diff
+35
View File
@@ -0,0 +1,35 @@
package types
import (
"context"
didtypes "github.com/sonr-io/sonr/x/did/types"
svctypes "github.com/sonr-io/sonr/x/svc/types"
)
// DIDKeeper interface defines the methods needed from the DID keeper
type DIDKeeper interface {
// ResolveDID resolves a DID to its DID document
ResolveDID(
ctx context.Context,
did string,
) (*didtypes.DIDDocument, *didtypes.DIDDocumentMetadata, error)
// GetDIDDocument gets a DID document by its ID
GetDIDDocument(ctx context.Context, did string) (*didtypes.DIDDocument, error)
}
// ServiceKeeper interface defines the methods needed from the Service keeper
type ServiceKeeper interface {
// VerifyServiceRegistration verifies service registration and domain ownership
VerifyServiceRegistration(ctx context.Context, serviceID string, domain string) (bool, error)
// GetService gets service by ID
GetService(ctx context.Context, serviceID string) (*svctypes.Service, error)
// IsDomainVerified checks if domain is verified
IsDomainVerified(ctx context.Context, domain string, owner string) (bool, error)
// GetServicesByDomain gets services by domain
GetServicesByDomain(ctx context.Context, domain string) ([]svctypes.Service, error)
}
Regular → Executable
-77
View File
@@ -1,25 +1,11 @@
package types
// Capability hierarchy for smart account operations
// ----------------------------------------------
// OWNER
//
// └─ OPERATOR
// ├─ EXECUTE
// ├─ PROPOSE
// └─ SIGN
// └─ SET_POLICY
// └─ SET_THRESHOLD
// └─ RECOVER
// └─ SOCIAL
//
// DefaultIndex is the default global index
const DefaultIndex uint64 = 1
// DefaultGenesis returns the default genesis state
func DefaultGenesis() *GenesisState {
return &GenesisState{
// this line is used by starport scaffolding # genesis/types/default
Params: DefaultParams(),
}
}
@@ -27,68 +13,5 @@ func DefaultGenesis() *GenesisState {
// Validate performs basic genesis state validation returning an error upon any
// failure.
func (gs GenesisState) Validate() error {
// this line is used by starport scaffolding # genesis/types/validate
return gs.Params.Validate()
}
// Equal checks if two Attenuation are equal
func (a *Attenuation) Equal(that *Attenuation) bool {
if that == nil {
return false
}
if a.Resource != nil {
if that.Resource == nil {
return false
}
if !a.Resource.Equal(that.Resource) {
return false
}
}
if len(a.Capabilities) != len(that.Capabilities) {
return false
}
for i := range a.Capabilities {
if !a.Capabilities[i].Equal(that.Capabilities[i]) {
return false
}
}
return true
}
// Equal checks if two Capability are equal
func (c *Capability) Equal(that *Capability) bool {
if that == nil {
return false
}
if c.Name != that.Name {
return false
}
if c.Parent != that.Parent {
return false
}
// TODO: check description
if len(c.Resources) != len(that.Resources) {
return false
}
for i := range c.Resources {
if c.Resources[i] != that.Resources[i] {
return false
}
}
return true
}
// Equal checks if two Resource are equal
func (r *Resource) Equal(that *Resource) bool {
if that == nil {
return false
}
if r.Kind != that.Kind {
return false
}
if r.Template != that.Template {
return false
}
return true
}
+791 -627
View File
File diff suppressed because it is too large Load Diff
-38
View File
@@ -1,38 +0,0 @@
package types_test
import (
"testing"
"github.com/sonr-io/snrd/x/dwn/types"
"github.com/stretchr/testify/require"
)
func TestGenesisState_Validate(t *testing.T) {
tests := []struct {
desc string
genState *types.GenesisState
valid bool
}{
{
desc: "default is valid",
genState: types.DefaultGenesis(),
valid: true,
},
{
desc: "valid genesis state",
genState: &types.GenesisState{},
valid: true,
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
err := tc.genState.Validate()
if tc.valid {
require.NoError(t, err)
} else {
require.Error(t, err)
}
})
}
}
Regular → Executable
+4 -4
View File
@@ -6,10 +6,8 @@ import (
ormv1alpha1 "cosmossdk.io/api/cosmos/orm/v1alpha1"
)
var (
// ParamsKey saves the current module params.
ParamsKey = collections.NewPrefix(0)
)
// ParamsKey saves the current module params.
var ParamsKey = collections.NewPrefix(0)
const (
ModuleName = "dwn"
@@ -17,6 +15,8 @@ const (
StoreKey = ModuleName
QuerierRoute = ModuleName
RouterKey = ModuleName
)
var ORMModuleSchema = ormv1alpha1.ModuleSchemaDescriptor{
Regular → Executable
+163 -16
View File
@@ -3,22 +3,28 @@ package types
import (
"cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
var _ sdk.Msg = &MsgUpdateParams{}
// ╭───────────────────────────────────────────────────────────╮
// │ MsgUpdateParams type definition │
// ╰───────────────────────────────────────────────────────────╯
var (
_ sdk.Msg = &MsgUpdateParams{}
_ sdk.Msg = &MsgRecordsWrite{}
_ sdk.Msg = &MsgRecordsDelete{}
_ sdk.Msg = &MsgProtocolsConfigure{}
_ sdk.Msg = &MsgPermissionsGrant{}
_ sdk.Msg = &MsgPermissionsRevoke{}
_ sdk.Msg = &MsgRotateVaultKeys{}
)
// NewMsgUpdateParams creates new instance of MsgUpdateParams
func NewMsgUpdateParams(
sender sdk.Address,
someValue bool,
params Params,
) *MsgUpdateParams {
return &MsgUpdateParams{
Authority: sender.String(),
Params: Params{},
Params: params,
}
}
@@ -28,22 +34,163 @@ func (msg MsgUpdateParams) Route() string { return ModuleName }
// Type returns the the action
func (msg MsgUpdateParams) Type() string { return "update_params" }
// GetSignBytes implements the LegacyMsg interface.
func (msg MsgUpdateParams) GetSignBytes() []byte {
return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg))
// GetSignBytes implements the Msg interface.
func (m MsgUpdateParams) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m))
}
// GetSigners returns the expected signers for a MsgUpdateParams message.
func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(msg.Authority)
func (m *MsgUpdateParams) GetSigners() []sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(m.Authority)
return []sdk.AccAddress{addr}
}
// ValidateBasic does a sanity check on the provided data.
func (msg *MsgUpdateParams) Validate() error {
if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil {
// Validate does a sanity check on the provided data.
func (m *MsgUpdateParams) Validate() error {
if _, err := sdk.AccAddressFromBech32(m.Authority); err != nil {
return errors.Wrap(err, "invalid authority address")
}
return msg.Params.Validate()
return m.Params.Validate()
}
// MsgRecordsWrite implementation
func (m *MsgRecordsWrite) GetSigners() []sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(m.Author)
return []sdk.AccAddress{addr}
}
func (m *MsgRecordsWrite) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(m.Author); err != nil {
return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid author address: %s", err)
}
if m.Target == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "target DID cannot be empty")
}
if m.Descriptor_ == nil {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "descriptor cannot be nil")
}
if len(m.Data) == 0 {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "data cannot be empty")
}
return nil
}
// MsgRecordsDelete implementation
func (m *MsgRecordsDelete) GetSigners() []sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(m.Author)
return []sdk.AccAddress{addr}
}
func (m *MsgRecordsDelete) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(m.Author); err != nil {
return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid author address: %s", err)
}
if m.Target == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "target DID cannot be empty")
}
if m.RecordId == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "record ID cannot be empty")
}
if m.Descriptor_ == nil {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "descriptor cannot be nil")
}
return nil
}
// MsgProtocolsConfigure implementation
func (m *MsgProtocolsConfigure) GetSigners() []sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(m.Author)
return []sdk.AccAddress{addr}
}
func (m *MsgProtocolsConfigure) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(m.Author); err != nil {
return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid author address: %s", err)
}
if m.Target == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "target DID cannot be empty")
}
if m.ProtocolUri == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "protocol URI cannot be empty")
}
if m.Descriptor_ == nil {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "descriptor cannot be nil")
}
if len(m.Definition) == 0 {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "definition cannot be empty")
}
return nil
}
// MsgPermissionsGrant implementation
func (m *MsgPermissionsGrant) GetSigners() []sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(m.Grantor)
return []sdk.AccAddress{addr}
}
func (m *MsgPermissionsGrant) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(m.Grantor); err != nil {
return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid grantor address: %s", err)
}
if m.Grantee == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "grantee DID cannot be empty")
}
if m.Target == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "target DID cannot be empty")
}
if m.InterfaceName == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "interface name cannot be empty")
}
if m.Method == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "method cannot be empty")
}
if m.Descriptor_ == nil {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "descriptor cannot be nil")
}
return nil
}
// MsgPermissionsRevoke implementation
// GetSigners returns the expected signers for a MsgPermissionsRevoke message.
func (m *MsgPermissionsRevoke) GetSigners() []sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(m.Grantor)
return []sdk.AccAddress{addr}
}
// ValidateBasic does a sanity check on the provided data
func (m *MsgPermissionsRevoke) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(m.Grantor); err != nil {
return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid grantor address: %s", err)
}
if m.PermissionId == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "permission ID cannot be empty")
}
if m.Descriptor_ == nil {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "descriptor cannot be nil")
}
return nil
}
// GetSigners returns the expected signers for a MsgRotateVaultKeys message
func (m *MsgRotateVaultKeys) GetSigners() []sdk.AccAddress {
addr, _ := sdk.AccAddressFromBech32(m.Authority)
return []sdk.AccAddress{addr}
}
// ValidateBasic does a sanity check on the provided data
func (m *MsgRotateVaultKeys) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(m.Authority); err != nil {
return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address: %s", err)
}
if m.Reason == "" {
return errors.Wrap(sdkerrors.ErrInvalidRequest, "reason cannot be empty")
}
return nil
}
// GetModuleAddress returns the dwn module account address
func GetModuleAddress() sdk.AccAddress {
return address.Module(ModuleName)
}
Regular → Executable
+163 -7
View File
@@ -2,20 +2,63 @@ package types
import (
"encoding/json"
"fmt"
)
const (
// Default max record size: 10MB
DefaultMaxRecordSize = 10 * 1024 * 1024
// Default max protocols per DWN: 100
DefaultMaxProtocolsPerDWN = 100
// Default max permissions per DWN: 1000
DefaultMaxPermissionsPerDWN = 1000
// Default vault creation enabled
DefaultVaultCreationEnabled = true
// Default min vault refresh interval: 100 blocks
DefaultMinVaultRefreshInterval = 100
// Default encryption enabled
DefaultEncryptionEnabled = true
// Default key rotation days: 30
DefaultKeyRotationDays = 30
// Default min validators for key generation: 67% of active set
DefaultMinValidatorsForKeyGen = 67
// Default single node fallback disabled
DefaultSingleNodeFallback = false
)
// DefaultEncryptedProtocols are protocols that require encryption by default
var DefaultEncryptedProtocols = []string{
"vault.enclave/v1", // SECURITY: Enclave data must always be encrypted
"medical.records/v1",
"financial.data/v1",
"private.messages/v1",
}
// DefaultEncryptedSchemas are schemas that require encryption by default
var DefaultEncryptedSchemas = []string{
"https://schemas.sonr.io/medical/",
"https://schemas.sonr.io/financial/",
"https://schemas.sonr.io/personal/",
}
// DefaultParams returns default module parameters.
func DefaultParams() Params {
return Params{
AllowedOperators: []string{ // TODO:
"localhost",
"didao.xyz",
"sonr.id",
},
MaxRecordSize: DefaultMaxRecordSize,
MaxProtocolsPerDwn: DefaultMaxProtocolsPerDWN,
MaxPermissionsPerDwn: DefaultMaxPermissionsPerDWN,
VaultCreationEnabled: DefaultVaultCreationEnabled,
MinVaultRefreshInterval: DefaultMinVaultRefreshInterval,
EncryptionEnabled: DefaultEncryptionEnabled,
KeyRotationDays: DefaultKeyRotationDays,
MinValidatorsForKeyGen: DefaultMinValidatorsForKeyGen,
EncryptedProtocols: DefaultEncryptedProtocols,
EncryptedSchemas: DefaultEncryptedSchemas,
SingleNodeFallback: DefaultSingleNodeFallback,
}
}
// Stringer method for Params.
// String method for Params.
func (p Params) String() string {
bz, err := json.Marshal(p)
if err != nil {
@@ -27,6 +70,119 @@ func (p Params) String() string {
// Validate does the sanity check on the params.
func (p Params) Validate() error {
// TODO:
if err := validateMaxRecordSize(p.MaxRecordSize); err != nil {
return err
}
if err := validateMaxProtocolsPerDWN(p.MaxProtocolsPerDwn); err != nil {
return err
}
if err := validateMaxPermissionsPerDWN(p.MaxPermissionsPerDwn); err != nil {
return err
}
if err := validateMinVaultRefreshInterval(p.MinVaultRefreshInterval); err != nil {
return err
}
if err := validateKeyRotationDays(p.KeyRotationDays); err != nil {
return err
}
if err := validateMinValidatorsForKeyGen(p.MinValidatorsForKeyGen); err != nil {
return err
}
if err := validateEncryptedProtocols(p.EncryptedProtocols); err != nil {
return err
}
if err := validateEncryptedSchemas(p.EncryptedSchemas); err != nil {
return err
}
return nil
}
func validateMaxRecordSize(maxSize uint64) error {
if maxSize == 0 {
return fmt.Errorf("max record size must be positive")
}
if maxSize > 100*1024*1024 { // 100MB max
return fmt.Errorf("max record size cannot exceed 100MB")
}
return nil
}
func validateMaxProtocolsPerDWN(max uint32) error {
if max == 0 {
return fmt.Errorf("max protocols per DWN must be positive")
}
if max > 10000 {
return fmt.Errorf("max protocols per DWN cannot exceed 10000")
}
return nil
}
func validateMaxPermissionsPerDWN(max uint32) error {
if max == 0 {
return fmt.Errorf("max permissions per DWN must be positive")
}
if max > 100000 {
return fmt.Errorf("max permissions per DWN cannot exceed 100000")
}
return nil
}
func validateMinVaultRefreshInterval(interval uint64) error {
if interval == 0 {
return fmt.Errorf("min vault refresh interval must be positive")
}
if interval > 1000000 {
return fmt.Errorf("min vault refresh interval cannot exceed 1000000 blocks")
}
return nil
}
func validateKeyRotationDays(days uint32) error {
if days == 0 {
return fmt.Errorf("key rotation days must be positive")
}
if days > 365 {
return fmt.Errorf("key rotation days cannot exceed 365")
}
return nil
}
func validateMinValidatorsForKeyGen(percentage uint32) error {
if percentage == 0 {
return fmt.Errorf("min validators percentage must be positive")
}
if percentage > 100 {
return fmt.Errorf("min validators percentage cannot exceed 100")
}
return nil
}
func validateEncryptedProtocols(protocols []string) error {
if len(protocols) > 1000 {
return fmt.Errorf("cannot have more than 1000 encrypted protocols")
}
for _, protocol := range protocols {
if protocol == "" {
return fmt.Errorf("encrypted protocol cannot be empty")
}
if len(protocol) > 256 {
return fmt.Errorf("encrypted protocol cannot exceed 256 characters")
}
}
return nil
}
func validateEncryptedSchemas(schemas []string) error {
if len(schemas) > 1000 {
return fmt.Errorf("cannot have more than 1000 encrypted schemas")
}
for _, schema := range schemas {
if schema == "" {
return fmt.Errorf("encrypted schema cannot be empty")
}
if len(schema) > 512 {
return fmt.Errorf("encrypted schema cannot exceed 512 characters")
}
}
return nil
}
+333
View File
@@ -0,0 +1,333 @@
package types
import (
"fmt"
"strings"
)
const (
unknownOperationString = "unknown"
// UCAN Action Constants for DWN operations (reference from ucan_capabilities.go)
UCANRecordsWrite = "records-write"
UCANRecordsDelete = "records-delete"
UCANRecordsRead = "records-read"
UCANRecordsQuery = "records-query"
UCANProtocolsConfigure = "protocols-configure"
UCANProtocolsQuery = "protocols-query"
UCANPermissionsGrant = "permissions-grant"
UCANPermissionsRevoke = "permissions-revoke"
UCANPermissionsQuery = "permissions-query"
UCANDataSync = "data-sync"
UCANMessageSync = "message-sync"
UCANCreate = "create"
UCANRead = "read"
UCANUpdate = "update"
UCANDelete = "delete"
UCANAdmin = "admin"
UCANAll = "*"
)
// DWNOperation represents different operations that can be performed on DWN
type DWNOperation int
const (
// Record operations
RecordCreate DWNOperation = iota
RecordRead
RecordUpdate
RecordDelete
RecordQuery
// Protocol operations
ProtocolInstall
ProtocolQuery
ProtocolUpdate
// Permission operations
PermissionGrant
PermissionRevoke
PermissionQuery
// Sync operations
DataSync
MessageSync
// Administrative operations
AdminConfig
AdminReset
)
// String returns the string representation of the operation
func (op DWNOperation) String() string {
switch op {
case RecordCreate:
return "record_create"
case RecordRead:
return "record_read"
case RecordUpdate:
return "record_update"
case RecordDelete:
return "record_delete"
case RecordQuery:
return "record_query"
case ProtocolInstall:
return "protocol_install"
case ProtocolQuery:
return "protocol_query"
case ProtocolUpdate:
return "protocol_update"
case PermissionGrant:
return "permission_grant"
case PermissionRevoke:
return "permission_revoke"
case PermissionQuery:
return "permission_query"
case DataSync:
return "data_sync"
case MessageSync:
return "message_sync"
case AdminConfig:
return "admin_config"
case AdminReset:
return "admin_reset"
default:
return unknownOperationString
}
}
// RecordOperation represents specific record operations
type RecordOperation int
const (
RecordOpCreate RecordOperation = iota
RecordOpRead
RecordOpUpdate
RecordOpDelete
RecordOpList
)
// String returns the string representation
func (op RecordOperation) String() string {
switch op {
case RecordOpCreate:
return "create"
case RecordOpRead:
return "read"
case RecordOpUpdate:
return "update"
case RecordOpDelete:
return "delete"
case RecordOpList:
return "list"
default:
return unknownOperationString
}
}
// ProtocolOperation represents specific protocol operations
type ProtocolOperation int
const (
ProtocolOpInstall ProtocolOperation = iota
ProtocolOpQuery
ProtocolOpUpdate
ProtocolOpDelete
)
// String returns the string representation
func (op ProtocolOperation) String() string {
switch op {
case ProtocolOpInstall:
return "install"
case ProtocolOpQuery:
return "query"
case ProtocolOpUpdate:
return "update"
case ProtocolOpDelete:
return "delete"
default:
return unknownOperationString
}
}
// PermissionRegistry manages DWN-specific UCAN capability mappings
type PermissionRegistry struct {
operationCapabilities map[DWNOperation][]string
recordCapabilities map[RecordOperation][]string
protocolCapabilities map[ProtocolOperation][]string
}
// NewDWNPermissionRegistry creates a new permission registry with UCAN-compatible capabilities
func NewDWNPermissionRegistry() PermissionRegistry {
registry := PermissionRegistry{
operationCapabilities: make(map[DWNOperation][]string),
recordCapabilities: make(map[RecordOperation][]string),
protocolCapabilities: make(map[ProtocolOperation][]string),
}
// Initialize UCAN-compatible operation capabilities
registry.operationCapabilities[RecordCreate] = []string{UCANRecordsWrite, UCANCreate}
registry.operationCapabilities[RecordRead] = []string{UCANRecordsRead, UCANRead}
registry.operationCapabilities[RecordUpdate] = []string{UCANRecordsWrite, UCANUpdate}
registry.operationCapabilities[RecordDelete] = []string{UCANRecordsDelete, UCANDelete}
registry.operationCapabilities[RecordQuery] = []string{UCANRecordsQuery, UCANRead}
registry.operationCapabilities[ProtocolInstall] = []string{UCANProtocolsConfigure, UCANCreate, UCANAdmin}
registry.operationCapabilities[ProtocolQuery] = []string{UCANProtocolsQuery, UCANRead}
registry.operationCapabilities[ProtocolUpdate] = []string{UCANProtocolsConfigure, UCANUpdate, UCANAdmin}
registry.operationCapabilities[PermissionGrant] = []string{UCANPermissionsGrant, UCANAdmin}
registry.operationCapabilities[PermissionRevoke] = []string{UCANPermissionsRevoke, UCANAdmin}
registry.operationCapabilities[PermissionQuery] = []string{UCANPermissionsQuery, UCANRead}
registry.operationCapabilities[DataSync] = []string{UCANDataSync, UCANRead, UCANUpdate}
registry.operationCapabilities[MessageSync] = []string{UCANMessageSync, UCANRead}
registry.operationCapabilities[AdminConfig] = []string{UCANAdmin}
registry.operationCapabilities[AdminReset] = []string{UCANAdmin, UCANDelete}
// Initialize UCAN-compatible record operation capabilities
registry.recordCapabilities[RecordOpCreate] = []string{UCANRecordsWrite, UCANCreate}
registry.recordCapabilities[RecordOpRead] = []string{UCANRecordsRead, UCANRead}
registry.recordCapabilities[RecordOpUpdate] = []string{UCANRecordsWrite, UCANUpdate}
registry.recordCapabilities[RecordOpDelete] = []string{UCANRecordsDelete, UCANDelete}
registry.recordCapabilities[RecordOpList] = []string{UCANRecordsQuery, UCANRead}
// Initialize UCAN-compatible protocol operation capabilities
registry.protocolCapabilities[ProtocolOpInstall] = []string{UCANProtocolsConfigure, UCANCreate}
registry.protocolCapabilities[ProtocolOpQuery] = []string{UCANProtocolsQuery, UCANRead}
registry.protocolCapabilities[ProtocolOpUpdate] = []string{UCANProtocolsConfigure, UCANUpdate}
registry.protocolCapabilities[ProtocolOpDelete] = []string{UCANProtocolsConfigure, UCANDelete}
return registry
}
// GetRequiredCapabilities returns the required UCAN capabilities for a DWN operation
func (pr *PermissionRegistry) GetRequiredCapabilities(operation DWNOperation) ([]string, error) {
capabilities, exists := pr.operationCapabilities[operation]
if !exists {
return nil, fmt.Errorf("no capabilities defined for operation: %s", operation.String())
}
return capabilities, nil
}
// GetRecordCapabilities returns the required capabilities for a record operation
func (pr *PermissionRegistry) GetRecordCapabilities(operation RecordOperation) []string {
if capabilities, exists := pr.recordCapabilities[operation]; exists {
return capabilities
}
return []string{"read"} // Default to read permission
}
// GetProtocolCapabilities returns the required capabilities for a protocol operation
func (pr *PermissionRegistry) GetProtocolCapabilities(operation ProtocolOperation) []string {
if capabilities, exists := pr.protocolCapabilities[operation]; exists {
return capabilities
}
return []string{"read"} // Default to read permission
}
// AddOperationCapabilities adds or updates capabilities for an operation
func (pr *PermissionRegistry) AddOperationCapabilities(
operation DWNOperation,
capabilities []string,
) {
pr.operationCapabilities[operation] = capabilities
}
// AddRecordCapabilities adds or updates capabilities for a record operation
func (pr *PermissionRegistry) AddRecordCapabilities(
operation RecordOperation,
capabilities []string,
) {
pr.recordCapabilities[operation] = capabilities
}
// AddProtocolCapabilities adds or updates capabilities for a protocol operation
func (pr *PermissionRegistry) AddProtocolCapabilities(
operation ProtocolOperation,
capabilities []string,
) {
pr.protocolCapabilities[operation] = capabilities
}
// ParseOperationFromString parses a string into a DWNOperation
func ParseOperationFromString(operationStr string) (DWNOperation, error) {
switch strings.ToLower(operationStr) {
case "record_create":
return RecordCreate, nil
case "record_read":
return RecordRead, nil
case "record_update":
return RecordUpdate, nil
case "record_delete":
return RecordDelete, nil
case "record_query":
return RecordQuery, nil
case "protocol_install":
return ProtocolInstall, nil
case "protocol_query":
return ProtocolQuery, nil
case "protocol_update":
return ProtocolUpdate, nil
case "permission_grant":
return PermissionGrant, nil
case "permission_revoke":
return PermissionRevoke, nil
case "permission_query":
return PermissionQuery, nil
case "data_sync":
return DataSync, nil
case "message_sync":
return MessageSync, nil
case "admin_config":
return AdminConfig, nil
case "admin_reset":
return AdminReset, nil
default:
return 0, fmt.Errorf("unknown operation: %s", operationStr)
}
}
// IsAdminOperation checks if the operation requires admin privileges
func IsAdminOperation(operation DWNOperation) bool {
switch operation {
case PermissionGrant, PermissionRevoke, AdminConfig, AdminReset:
return true
case ProtocolInstall, ProtocolUpdate:
return true
default:
return false
}
}
// IsWriteOperation checks if the operation requires write privileges
func IsWriteOperation(operation DWNOperation) bool {
switch operation {
case RecordCreate, RecordUpdate, RecordDelete:
return true
case ProtocolInstall, ProtocolUpdate:
return true
case DataSync:
return true
default:
return false
}
}
// IsReadOperation checks if the operation requires read privileges
func IsReadOperation(operation DWNOperation) bool {
switch operation {
case RecordRead, RecordQuery:
return true
case ProtocolQuery:
return true
case PermissionQuery:
return true
case MessageSync:
return true
default:
return false
}
}
+6425 -22
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+139
View File
@@ -0,0 +1,139 @@
package types
import (
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// WalletSponsorship represents metadata for a wallet sponsorship
// This stores additional data beyond what BasicAllowance provides
type WalletSponsorship struct {
// Core sponsorship info
Granter string `json:"granter"` // Address of the sponsor
Grantee string `json:"grantee"` // Address of the sponsored wallet
WalletAddress string `json:"wallet_address"` // Same as grantee for simplicity
VaultId string `json:"vault_id"` // Associated vault ID
CreatedAt time.Time `json:"created_at"` // Creation timestamp
// Additional restrictions (not enforced by BasicAllowance)
DailyLimit *sdk.Coins `json:"daily_limit,omitempty"` // Optional daily limit
AllowedMessages []string `json:"allowed_messages,omitempty"` // Optional message restrictions
// Usage tracking (managed by our keeper)
DailySpent sdk.Coins `json:"daily_spent"` // Amount spent today
LastResetDate time.Time `json:"last_reset_date"` // Last daily reset
LastUsedAt *time.Time `json:"last_used_at,omitempty"`
}
// SponsorshipInfo represents sponsorship information for queries
type SponsorshipInfo struct {
Granter string `json:"granter"`
Grantee string `json:"grantee"`
WalletAddress string `json:"wallet_address"`
VaultId string `json:"vault_id"`
SpendLimit *sdk.Coins `json:"spend_limit,omitempty"`
Expiration *time.Time `json:"expiration,omitempty"`
DailyLimit *sdk.Coins `json:"daily_limit,omitempty"`
AllowedMessages []string `json:"allowed_messages,omitempty"`
CreatedAt time.Time `json:"created_at"`
DailySpent sdk.Coins `json:"daily_spent"`
LastUsedAt *time.Time `json:"last_used_at,omitempty"`
}
// GaslessTransactionResponse represents the response from a gasless transaction
type GaslessTransactionResponse struct {
Success bool `json:"success"`
TxHash string `json:"tx_hash"`
WalletAddress string `json:"wallet_address"`
GasUsed uint64 `json:"gas_used"`
FeesDeducted sdk.Coins `json:"fees_deducted"`
}
// ValidateBasic performs basic validation on WalletSponsorship
func (ws *WalletSponsorship) ValidateBasic() error {
if ws.Granter == "" {
return ErrInvalidWalletAddress.Wrap("granter address is empty")
}
if ws.Grantee == "" {
return ErrInvalidWalletAddress.Wrap("grantee address is empty")
}
if ws.VaultId == "" {
return ErrVaultIDEmpty
}
// Validate addresses
if _, err := sdk.AccAddressFromBech32(ws.Granter); err != nil {
return ErrInvalidWalletAddress.Wrapf("invalid granter address: %s", err)
}
if _, err := sdk.AccAddressFromBech32(ws.Grantee); err != nil {
return ErrInvalidWalletAddress.Wrapf("invalid grantee address: %s", err)
}
// Validate daily limit if present
if ws.DailyLimit != nil {
if !ws.DailyLimit.IsValid() {
return ErrInvalidSpendLimit.Wrap("daily limit is invalid")
}
if !ws.DailyLimit.IsAllPositive() {
return ErrInvalidSpendLimit.Wrap("daily limit must be positive")
}
}
return nil
}
// IsDailyLimitExceeded checks if the daily limit would be exceeded by the given amount
func (ws *WalletSponsorship) IsDailyLimitExceeded(amount sdk.Coins) bool {
if ws.DailyLimit == nil {
return false // No daily limit
}
// Reset daily spent if it's a new day
now := time.Now()
if now.Day() != ws.LastResetDate.Day() || now.Month() != ws.LastResetDate.Month() ||
now.Year() != ws.LastResetDate.Year() {
ws.DailySpent = sdk.NewCoins()
ws.LastResetDate = now
}
// Check if adding this amount would exceed the daily limit
totalSpent := ws.DailySpent.Add(amount...)
for _, limitCoin := range *ws.DailyLimit {
spentAmount := totalSpent.AmountOf(limitCoin.Denom)
if spentAmount.GT(limitCoin.Amount) {
return true
}
}
return false
}
// AddDailySpent adds to the daily spent amount and updates the last used time
func (ws *WalletSponsorship) AddDailySpent(amount sdk.Coins) {
now := time.Now()
// Reset daily spent if it's a new day
if now.Day() != ws.LastResetDate.Day() || now.Month() != ws.LastResetDate.Month() ||
now.Year() != ws.LastResetDate.Year() {
ws.DailySpent = sdk.NewCoins()
ws.LastResetDate = now
}
ws.DailySpent = ws.DailySpent.Add(amount...)
ws.LastUsedAt = &now
}
// IsMessageAllowed checks if a message type is allowed by this sponsorship
func (ws *WalletSponsorship) IsMessageAllowed(msgTypeURL string) bool {
if len(ws.AllowedMessages) == 0 {
return true // No restrictions
}
for _, allowed := range ws.AllowedMessages {
if allowed == msgTypeURL {
return true
}
}
return false
}
+6216 -286
View File
File diff suppressed because it is too large Load Diff
+4224 -136
View File
File diff suppressed because it is too large Load Diff
+306
View File
@@ -0,0 +1,306 @@
package types
import (
"fmt"
"strings"
"github.com/sonr-io/sonr/crypto/ucan"
)
// UCAN Action Constants are defined in permissions.go
// UCANCapabilityMapper provides conversion between DWN operations and UCAN capabilities
type UCANCapabilityMapper struct{}
// NewUCANCapabilityMapper creates a new capability mapper
func NewUCANCapabilityMapper() *UCANCapabilityMapper {
return &UCANCapabilityMapper{}
}
// GetUCANCapabilitiesForOperation returns UCAN-specific capabilities for a DWN operation
func (m *UCANCapabilityMapper) GetUCANCapabilitiesForOperation(operation DWNOperation) []string {
switch operation {
case RecordCreate:
return []string{UCANRecordsWrite, UCANCreate}
case RecordRead:
return []string{UCANRecordsRead, UCANRead}
case RecordUpdate:
return []string{UCANRecordsWrite, UCANUpdate}
case RecordDelete:
return []string{UCANRecordsDelete, UCANDelete}
case RecordQuery:
return []string{UCANRecordsQuery, UCANRead}
case ProtocolInstall:
return []string{UCANProtocolsConfigure, UCANCreate, UCANAdmin}
case ProtocolQuery:
return []string{UCANProtocolsQuery, UCANRead}
case ProtocolUpdate:
return []string{UCANProtocolsConfigure, UCANUpdate, UCANAdmin}
case PermissionGrant:
return []string{UCANPermissionsGrant, UCANAdmin}
case PermissionRevoke:
return []string{UCANPermissionsRevoke, UCANAdmin}
case PermissionQuery:
return []string{UCANPermissionsQuery, UCANRead}
case DataSync:
return []string{UCANDataSync, UCANRead, UCANUpdate}
case MessageSync:
return []string{UCANMessageSync, UCANRead}
case AdminConfig:
return []string{UCANAdmin}
case AdminReset:
return []string{UCANAdmin, UCANDelete}
default:
return []string{UCANRead} // Default to read permission
}
}
// GetUCANCapabilitiesForRecordOperation returns UCAN capabilities for record operations
func (m *UCANCapabilityMapper) GetUCANCapabilitiesForRecordOperation(operation RecordOperation) []string {
switch operation {
case RecordOpCreate:
return []string{UCANRecordsWrite, UCANCreate}
case RecordOpRead:
return []string{UCANRecordsRead, UCANRead}
case RecordOpUpdate:
return []string{UCANRecordsWrite, UCANUpdate}
case RecordOpDelete:
return []string{UCANRecordsDelete, UCANDelete}
case RecordOpList:
return []string{UCANRecordsQuery, UCANRead}
default:
return []string{UCANRead}
}
}
// GetUCANCapabilitiesForProtocolOperation returns UCAN capabilities for protocol operations
func (m *UCANCapabilityMapper) GetUCANCapabilitiesForProtocolOperation(operation ProtocolOperation) []string {
switch operation {
case ProtocolOpInstall:
return []string{UCANProtocolsConfigure, UCANCreate}
case ProtocolOpQuery:
return []string{UCANProtocolsQuery, UCANRead}
case ProtocolOpUpdate:
return []string{UCANProtocolsConfigure, UCANUpdate}
case ProtocolOpDelete:
return []string{UCANProtocolsConfigure, UCANDelete}
default:
return []string{UCANRead}
}
}
// CreateDWNResourceURI builds a DWN resource URI for UCAN validation
func (m *UCANCapabilityMapper) CreateDWNResourceURI(target, resourceType, resourceID string) string {
if resourceID != "" {
return fmt.Sprintf("dwn://%s/%s/%s", target, resourceType, resourceID)
}
return fmt.Sprintf("dwn://%s/%s", target, resourceType)
}
// CreateRecordResourceURI builds a resource URI for a specific record
func (m *UCANCapabilityMapper) CreateRecordResourceURI(target, recordID string) string {
return m.CreateDWNResourceURI(target, "records", recordID)
}
// CreateProtocolResourceURI builds a resource URI for a protocol
func (m *UCANCapabilityMapper) CreateProtocolResourceURI(target, protocolURI string) string {
return m.CreateDWNResourceURI(target, "protocols", protocolURI)
}
// CreatePermissionResourceURI builds a resource URI for permissions
func (m *UCANCapabilityMapper) CreatePermissionResourceURI(target string) string {
return m.CreateDWNResourceURI(target, "permissions", "")
}
// CreateDWNAttenuation creates a UCAN attenuation for DWN operations
func (m *UCANCapabilityMapper) CreateDWNAttenuation(
actions []string,
target, recordType, protocol string,
) ucan.Attenuation {
resourceURI := m.CreateDWNResourceURI(target, "records", "")
resource := &ucan.DWNResource{
SimpleResource: ucan.SimpleResource{
Scheme: "dwn",
Value: fmt.Sprintf("records/%s", target),
URI: resourceURI,
},
RecordType: recordType,
Protocol: protocol,
Owner: target,
}
capability := &ucan.DWNCapability{
Actions: actions,
}
return ucan.Attenuation{
Capability: capability,
Resource: resource,
}
}
// CreateRecordAttenuation creates a UCAN attenuation for specific record operations
func (m *UCANCapabilityMapper) CreateRecordAttenuation(
actions []string,
target, recordID, recordType string,
) ucan.Attenuation {
resourceURI := m.CreateRecordResourceURI(target, recordID)
resource := &ucan.DWNResource{
SimpleResource: ucan.SimpleResource{
Scheme: "dwn",
Value: fmt.Sprintf("records/%s", recordID),
URI: resourceURI,
},
RecordType: recordType,
Owner: target,
}
capability := &ucan.DWNCapability{
Actions: actions,
}
return ucan.Attenuation{
Capability: capability,
Resource: resource,
}
}
// CreateProtocolAttenuation creates a UCAN attenuation for protocol operations
func (m *UCANCapabilityMapper) CreateProtocolAttenuation(
actions []string,
target, protocolURI string,
) ucan.Attenuation {
resourceURI := m.CreateProtocolResourceURI(target, protocolURI)
resource := &ucan.DWNResource{
SimpleResource: ucan.SimpleResource{
Scheme: "dwn",
Value: fmt.Sprintf("protocols/%s", protocolURI),
URI: resourceURI,
},
Protocol: protocolURI,
Owner: target,
}
capability := &ucan.DWNCapability{
Actions: actions,
}
return ucan.Attenuation{
Capability: capability,
Resource: resource,
}
}
// ValidateUCANCapabilities validates that a UCAN capability grants the required DWN actions
func (m *UCANCapabilityMapper) ValidateUCANCapabilities(
capability ucan.Capability,
requiredActions []string,
) bool {
return capability.Grants(requiredActions)
}
// ConvertLegacyCapabilities converts old string-based capabilities to UCAN format
func (m *UCANCapabilityMapper) ConvertLegacyCapabilities(legacyCapabilities []string) []string {
var ucanCapabilities []string
for _, legacy := range legacyCapabilities {
switch strings.ToLower(legacy) {
case "write", "create":
ucanCapabilities = append(ucanCapabilities, UCANCreate)
case "read", "list", "query":
ucanCapabilities = append(ucanCapabilities, UCANRead)
case "update":
ucanCapabilities = append(ucanCapabilities, UCANUpdate)
case "delete":
ucanCapabilities = append(ucanCapabilities, UCANDelete)
case "admin":
ucanCapabilities = append(ucanCapabilities, UCANAdmin)
case "sync":
ucanCapabilities = append(ucanCapabilities, UCANDataSync)
case "*":
ucanCapabilities = append(ucanCapabilities, UCANAll)
default:
// Pass through unknown capabilities
ucanCapabilities = append(ucanCapabilities, legacy)
}
}
return ucanCapabilities
}
// IsUCANAction checks if an action string is a valid UCAN action
func IsUCANAction(action string) bool {
validActions := []string{
UCANRecordsWrite, UCANRecordsDelete, UCANRecordsRead, UCANRecordsQuery,
UCANProtocolsConfigure, UCANProtocolsQuery,
UCANPermissionsGrant, UCANPermissionsRevoke, UCANPermissionsQuery,
UCANDataSync, UCANMessageSync,
UCANCreate, UCANRead, UCANUpdate, UCANDelete,
UCANAdmin, UCANAll,
}
for _, validAction := range validActions {
if action == validAction {
return true
}
}
return false
}
// GetDWNCapabilityTemplate returns a preconfigured capability template for DWN
func GetDWNCapabilityTemplate() *ucan.CapabilityTemplate {
return ucan.StandardDWNTemplate()
}
// UCANPermissionRegistry extends the basic permission registry with UCAN capabilities
type UCANPermissionRegistry struct {
*PermissionRegistry
mapper *UCANCapabilityMapper
}
// NewUCANPermissionRegistry creates a new UCAN-aware permission registry
func NewUCANPermissionRegistry() *UCANPermissionRegistry {
return &UCANPermissionRegistry{
PermissionRegistry: &PermissionRegistry{
operationCapabilities: make(map[DWNOperation][]string),
recordCapabilities: make(map[RecordOperation][]string),
protocolCapabilities: make(map[ProtocolOperation][]string),
},
mapper: NewUCANCapabilityMapper(),
}
}
// GetRequiredUCANCapabilities returns UCAN-specific capabilities for a DWN operation
func (r *UCANPermissionRegistry) GetRequiredUCANCapabilities(operation DWNOperation) ([]string, error) {
capabilities := r.mapper.GetUCANCapabilitiesForOperation(operation)
if len(capabilities) == 0 {
return nil, fmt.Errorf("no UCAN capabilities defined for operation: %s", operation.String())
}
return capabilities, nil
}
// GetRecordUCANCapabilities returns UCAN capabilities for record operations
func (r *UCANPermissionRegistry) GetRecordUCANCapabilities(operation RecordOperation) []string {
return r.mapper.GetUCANCapabilitiesForRecordOperation(operation)
}
// GetProtocolUCANCapabilities returns UCAN capabilities for protocol operations
func (r *UCANPermissionRegistry) GetProtocolUCANCapabilities(operation ProtocolOperation) []string {
return r.mapper.GetUCANCapabilitiesForProtocolOperation(operation)
}
// CreateDWNAttenuation creates a UCAN attenuation for DWN operations
func (r *UCANPermissionRegistry) CreateDWNAttenuation(
actions []string,
target, recordType, protocol string,
) ucan.Attenuation {
return r.mapper.CreateDWNAttenuation(actions, target, recordType, protocol)
}
+34
View File
@@ -0,0 +1,34 @@
package types
// VaultMetadata contains metadata about an encrypted vault
type VaultMetadata struct {
Did string `json:"did"`
VaultId string `json:"vault_id"`
Owner string `json:"owner"`
KeyId string `json:"key_id"`
Algorithm string `json:"algorithm"`
Nonce string `json:"nonce"`
CreatedAt int64 `json:"created_at"`
BlockHeight int64 `json:"block_height"`
ValidatorSet []string `json:"validator_set"`
}
// EncryptedVaultData represents encrypted vault data stored in IPFS
type EncryptedVaultData struct {
Metadata *VaultMetadata `json:"metadata"`
EncryptedData string `json:"encrypted_data"`
Version int `json:"version"`
}
// EncryptedVaultState represents the on-chain state of an encrypted vault
type EncryptedVaultState struct {
VaultId string `json:"vault_id"`
Did string `json:"did"`
Owner string `json:"owner"`
IpfsCid string `json:"ipfs_cid"`
PublicKey string `json:"public_key"`
CreatedAt int64 `json:"created_at"`
LastUpdated int64 `json:"last_updated"`
Status string `json:"status"`
EncryptionType string `json:"encryption_type"`
}