Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions app/console/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ async function toDelegation (car: Blob): Promise<Delegation> {
export default function Console () {
const agent = useAgent()
const agentDID = agent?.did()
const [delegations, setDelegations] = useState<Delegation<Capabilities>[]>([])
if (agent) {
setDelegations(agent.proofs())
}
const [storedDelegations, setDelegations] = useState<Delegation<Capabilities>[]>([])
const delegations = storedDelegations ?? agent?.proofs()
const [configuredServiceSigner, setConfiguredServiceSigner] = useState<Ucanto.Signer>()
const [expiry, setExpiry] = useState<number>(30)
const { servicePrincipal } = useContext(ServiceContext)
Expand All @@ -48,6 +46,7 @@ export default function Console () {
{ with: servicePrincipal.did(), can: 'subscription/get' },
{ with: servicePrincipal.did(), can: 'rate-limit/*' },
{ with: servicePrincipal.did(), can: 'admin/*' },
{ with: 'ucan:*', can: 'account/usage/get' },
],
expiration: Math.floor(Date.now() / 1000) + (60 * expiry)
})
Expand Down Expand Up @@ -92,7 +91,10 @@ export default function Console () {
{ with: '${servicePrincipal?.did()}', can: 'consumer/get' },
{ with: '${servicePrincipal?.did()}', can: 'subscription/get' },
{ with: '${servicePrincipal?.did()}', can: 'rate-limit/*' },
{ with: '${servicePrincipal?.did()}', can: 'admin/*' },
{ with: 'ucan:*', can: 'account/usage/get' },
]`

return (
<div className='flex flex-col items-center'>
{
Expand Down
24 changes: 23 additions & 1 deletion app/customers/[did]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Link from "next/link";
import { notFound } from "next/navigation";
import * as DidMailto from "@storacha/did-mailto";

import { useCustomer } from "@/hooks/customer";
import { useCustomer, useCustomerUsage } from "@/hooks/customer";
import { useRateLimitActions } from "@/hooks/rate-limit";
import { SimpleError } from "@/components/error";
import { Loader } from "@/components/brand";
Expand Down Expand Up @@ -33,6 +33,7 @@ export default function Customer(props: { params: Promise<{ did: string }> }) {

console.log(did)
const { data: customer, error, isLoading } = useCustomer(did);
const {data: usage} = useCustomerUsage(did)
const {
addBlock: addEmailBlock,
removeBlock: removeEmailBlock,
Expand Down Expand Up @@ -105,6 +106,27 @@ export default function Customer(props: { params: Promise<{ did: string }> }) {
))}
</tbody>
</table>
<h3 className="text-xl mb-2">Usage</h3>
<h4>{usage?.total} bytes</h4>
<table className="border-separate border-spacing-x-4">
<tbody>
{Object.entries(usage?.spaces || {}).map(([did, storage]) => (
<tr key={did}>
<td>
{did}
</td>
<td>
<Link
className="underline text-blue-200"
href={`/spaces/${did}`}
>
{storage.total}bytes
</Link>
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function RootLayout({
<ServiceProvider>
<AgentProvider>
<html>
<body className="min-h-screen bg-slate-800 text-white">
<body className="min-h-screen bg-red-800 text-white">
<Nav />
<main className="grow text-white p-4">
<AuthenticationEnsurer>{children}</AuthenticationEnsurer>
Expand Down
2 changes: 1 addition & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function Root () {
}, [router, cid])
return (
<div className='flex flex-col items-center'>
<h1 className='text-xl mb-10'>w3admin</h1>
<h1 className='text-xl mb-10'>Sudoracha</h1>
<form onSubmit={goToSpace} className='flex flex-col space-y-2 mb-16 items-center'>
<input className='text-black py-1 px-2 rounded' type='text' placeholder="Space DID" onChange={(e: ChangeEvent<HTMLInputElement>) => setSpaceDID(e.target.value)} />
<input className='btn w-24' type='submit' value='Go' />
Expand Down
14 changes: 13 additions & 1 deletion contexts/service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ import {
AdminUploadInspectSuccess,
AdminUploadInspectFailure,
AdminStoreInspectSuccess,
AdminStoreInspectFailure
AdminStoreInspectFailure,
AccountUsageGet,
AccountUsageGetSuccess,
AccountUsageGetFailure
} from "@storacha/capabilities/types"
import { Absentee } from "@ucanto/principal"
import { useW3 } from "@storacha/ui-react"
Expand Down Expand Up @@ -78,6 +81,15 @@ export interface Service {
RateLimitListFailure
>
},
account: {
usage: {
get: ServiceMethod<
AccountUsageGet,
AccountUsageGetSuccess,
AccountUsageGetFailure
>
}
}
admin: {
upload: {
inspect: ServiceMethod<
Expand Down
25 changes: 24 additions & 1 deletion hooks/customer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import useSWR from 'swr'
import { DID } from '@ucanto/interface'
import { Customer } from '@storacha/capabilities'
import { Customer, AccountUsage } from '@storacha/capabilities'
import { useAgent } from './agent'
import { useServicePrincipal } from './service'

Expand All @@ -27,4 +27,27 @@ export function useCustomer (did: string | undefined) {
return null
}
})
}

export function useCustomerUsage (did: string | undefined) {
const agent = useAgent()
const servicePrincipal = useServicePrincipal()
return useSWR(
(did && agent && servicePrincipal) ? ['account/usage/get', did] : null,
async ([, did]: [never, string | undefined]) => {
if (did && agent && servicePrincipal) {
const result = await agent?.invokeAndExecute(AccountUsage.get, {
with: did as DID<'mailto'>,
nb: {}
})
if (result.out.ok) {
return result.out.ok
} else {
console.error('Customer.get failed:', result.out.error)
throw result.out.error
}
} else {
return null
}
})
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"@ipld/car": "^5.4.2",
"@ipld/dag-ucan": "^3.4.5",
"@storacha/access": "^1.6.2",
"@storacha/capabilities": "^1.10.0",
"@storacha/capabilities": "^1.12.0",
"@storacha/client": "^1.8.12",
"@storacha/did-mailto": "^1.0.2",
"@storacha/ui-react": "^2.9.75",
Expand Down
39 changes: 39 additions & 0 deletions scripts/grant-admin-rights.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { delegate } from '@ucanto/core'
import { create } from '@storacha/client'
import * as Signer from '@ucanto/principal/ed25519'
import { Absentee } from '@ucanto/principal'
import * as DIDMailto from '@storacha/did-mailto'
import { MemoryDriver } from '@storacha/access/drivers/memory'

// 90 days, in minutes
const EXPIRY = 60 * 24 * 90

// this must be run with the private key of the service passed as SERVICE_PRIVATE_KEY
const servicePrincipal = process.env.SERVICE_PRIVATE_KEY ? Signer.parse(process.env.SERVICE_PRIVATE_KEY) : undefined
if (!servicePrincipal) throw new Error("Principal not defined, can't continue.")

const delegateeEmail = process.argv[2] as `${string}@${string}`
const delegateeDidMailto = DIDMailto.fromEmail(delegateeEmail)

const client = await create({ principal: servicePrincipal, store: new MemoryDriver() })
console.log(servicePrincipal.toDIDKey())
const delegation = await delegate({
issuer: servicePrincipal,
audience: Absentee.from({ id: delegateeDidMailto }),
// grant capabilities needed for admin work
capabilities: [
{ with: servicePrincipal.did(), can: 'customer/get' },
{ with: servicePrincipal.did(), can: 'consumer/get' },
{ with: servicePrincipal.did(), can: 'subscription/get' },
{ with: servicePrincipal.did(), can: 'rate-limit/*' },
{ with: servicePrincipal.did(), can: 'admin/*' },
],
expiration: Math.floor(Date.now() / 1000) + (60 * EXPIRY)
})
const result = await client.capability.access.delegate({
// use the did:key of the service principal as the space to store the delegation in
space: servicePrincipal.toDIDKey(),
delegations: [delegation]
})

console.log(result)
Loading