diff --git a/package-lock.json b/package-lock.json index 1c6f9e4..888a84f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,13 @@ "version": "2.36.0", "license": "Apache-2.0 OR MIT", "dependencies": { + "@ipld/dag-json": "^10.2.5", "@ipld/dag-pb": "^4.1.5", "@microlabs/otel-cf-workers": "^1.0.0-rc.48", "@opentelemetry/api": "^1.9.0", "@opentelemetry/sdk-trace-base": "^1.27.0", "@storacha/capabilities": "^1.10.0", - "@storacha/indexing-service-client": "^2.6.6", + "@storacha/indexing-service-client": "^2.6.9", "@types/node": "^24.10.1", "@ucanto/client": "^9.0.2", "@ucanto/core": "^10.4.5", @@ -23,7 +24,7 @@ "@ucanto/server": "^11.0.3", "@ucanto/transport": "^9.2.1", "@ucanto/validator": "^10.0.1", - "@web3-storage/blob-fetcher": "^4.2.5", + "@web3-storage/blob-fetcher": "^4.2.6", "@web3-storage/gateway-lib": "^5.2.2", "dagula": "^8.0.0", "http-range-parse": "^1.0.0", @@ -31,6 +32,7 @@ "multiformats": "^13.0.1" }, "devDependencies": { + "@ipld/dag-ucan": "^3.4.5", "@storacha/blob-index": "^1.2.4", "@storacha/cli": "^1.6.2", "@storacha/client": "^1.8.2", @@ -6077,9 +6079,9 @@ "license": "ISC" }, "node_modules/@web3-storage/blob-fetcher": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/@web3-storage/blob-fetcher/-/blob-fetcher-4.2.5.tgz", - "integrity": "sha512-wfs8XNcgp5nE7zFidUG7L/QL5MxCCK1a22ly8meRgHScycSJCu1OXEGGYY9wxOXgkQxZ8S65Kkn/TIh8xGgUZg==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@web3-storage/blob-fetcher/-/blob-fetcher-4.2.6.tgz", + "integrity": "sha512-4svLIamPg7tjIDJK3vKmNq4XagggcfSKNRp3EbVtJA5lRdBYjj7h19242TMB/3iL8rvU36vMZKCFldNGAKnk5Q==", "license": "Apache-2.0 OR MIT", "dependencies": { "@cloudflare/workers-types": "^4.20241022.0", diff --git a/package.json b/package.json index db34e57..e628201 100644 --- a/package.json +++ b/package.json @@ -36,12 +36,13 @@ "test:unit:only": "npm run build:debug && mocha --experimental-vm-modules" }, "dependencies": { + "@ipld/dag-json": "^10.2.5", "@ipld/dag-pb": "^4.1.5", "@microlabs/otel-cf-workers": "^1.0.0-rc.48", "@opentelemetry/api": "^1.9.0", "@opentelemetry/sdk-trace-base": "^1.27.0", "@storacha/capabilities": "^1.10.0", - "@storacha/indexing-service-client": "^2.6.6", + "@storacha/indexing-service-client": "^2.6.9", "@types/node": "^24.10.1", "@ucanto/client": "^9.0.2", "@ucanto/core": "^10.4.5", @@ -50,7 +51,7 @@ "@ucanto/server": "^11.0.3", "@ucanto/transport": "^9.2.1", "@ucanto/validator": "^10.0.1", - "@web3-storage/blob-fetcher": "^4.2.5", + "@web3-storage/blob-fetcher": "^4.2.6", "@web3-storage/gateway-lib": "^5.2.2", "dagula": "^8.0.0", "http-range-parse": "^1.0.0", @@ -58,6 +59,7 @@ "multiformats": "^13.0.1" }, "devDependencies": { + "@ipld/dag-ucan": "^3.4.5", "@storacha/blob-index": "^1.2.4", "@storacha/cli": "^1.6.2", "@storacha/client": "^1.8.2", diff --git a/scripts/mk-validator-proof.js b/scripts/mk-validator-proof.js new file mode 100644 index 0000000..b92539f --- /dev/null +++ b/scripts/mk-validator-proof.js @@ -0,0 +1,91 @@ +/** + * Create a "ucan/attest" delegation allowing the gateway to validate + * attestations issued by the upload-service. + * + * This generates the GATEWAY_VALIDATOR_PROOF environment variable value. + * + * Usage: node scripts/mk-validator-proof.js + * + * Example (staging): + * node scripts/mk-validator-proof.js \ + * did:web:staging.up.storacha.network \ + * MgCZT5J+...your-key-here... \ + * did:web:staging.w3s.link + * + * Example (production): + * node scripts/mk-validator-proof.js \ + * did:web:up.storacha.network \ + * MgCZT5J+...your-key-here... \ + * did:web:w3s.link + */ +import * as DID from '@ipld/dag-ucan/did' +import { CAR, delegate } from '@ucanto/core' +import * as ed25519 from '@ucanto/principal/ed25519' +import { base64 } from 'multiformats/bases/base64' +import { identity } from 'multiformats/hashes/identity' +import * as Link from 'multiformats/link' + +// CORRECT DIRECTION (staging): +// - issuer should be did:web:staging.up.storacha.network (upload-service) +// - audience should be did:web:staging.w3s.link (gateway) +// - can should be 'ucan/attest' +// - with should be issuer.did() (i.e. did:web:staging.up.storacha.network) +// The private key must be the upload-service private key. This makes the +// gateway trust attestations issued by the upload-service. + +const uploadServiceDIDWeb = process.argv[2] +const uploadServicePrivateKey = process.argv[3] +const gatewayDIDWeb = process.argv[4] + +if (!uploadServiceDIDWeb || !uploadServicePrivateKey || !gatewayDIDWeb) { + console.error('Error: Missing required arguments') + console.error('Usage: node scripts/mk-validator-proof.js ') + console.error('') + console.error('Example (staging):') + console.error(' node scripts/mk-validator-proof.js \\') + console.error(' did:web:staging.up.storacha.network \\') + console.error(' MgCZT5J+...your-key-here... \\') + console.error(' did:web:staging.w3s.link') + process.exit(1) +} + +console.log(`Upload Service DID: ${uploadServiceDIDWeb}`) +console.log(`Upload Service Private Key: ${uploadServicePrivateKey.slice(0, 7)}...${uploadServicePrivateKey.slice(-7)}`) +console.log(`Gateway DID: ${gatewayDIDWeb}`) +console.log('') + +const issuer = ed25519 + .parse(uploadServicePrivateKey) + .withDID(DID.parse(uploadServiceDIDWeb).did()) +const audience = DID.parse(gatewayDIDWeb) + +// Note: variable names are confusing - "uploadService" is actually the issuer (gateway in our case) +// and "gateway" is actually the audience (upload service in our case) +// The 'with' should be the issuer's DID per colleague's instructions +const delegation = await delegate({ + issuer, + audience, + capabilities: [{ can: 'ucan/attest', with: issuer.did() }], + expiration: Infinity +}) + +console.log('✅ Delegation created:') +console.log(` Issuer: ${issuer.did()}`) +console.log(` Audience: ${audience.did()}`) +console.log(` Capability: ucan/attest with ${issuer.did()}`) +console.log('') + +const res = await delegation.archive() +if (res.error) { + console.error('❌ Error archiving delegation:', res.error) + throw res.error +} + +const proof = Link.create(CAR.code, identity.digest(res.ok)).toString(base64) + +console.log('✅ Validator proof generated successfully!') +console.log('') +console.log('Add this to your environment variables:') +console.log('') +console.log('GATEWAY_VALIDATOR_PROOF=' + proof) +console.log('') diff --git a/src/bindings.d.ts b/src/bindings.d.ts index 09411f3..8295cc6 100644 --- a/src/bindings.d.ts +++ b/src/bindings.d.ts @@ -26,4 +26,5 @@ export interface Environment HONEYCOMB_API_KEY: string FF_TELEMETRY_ENABLED: string TELEMETRY_RATIO: string + GATEWAY_VALIDATOR_PROOF?: string } diff --git a/src/middleware/withAuthorizedSpace.js b/src/middleware/withAuthorizedSpace.js index 55a5019..a5e2eb9 100644 --- a/src/middleware/withAuthorizedSpace.js +++ b/src/middleware/withAuthorizedSpace.js @@ -1,5 +1,6 @@ import { Verifier } from '@ucanto/principal' import { ok, access, fail, Unauthorized } from '@ucanto/validator' +import { resolveDIDKey, getValidatorProofs } from '../server/index.js' import { HttpError } from '@web3-storage/gateway-lib/util' import * as serve from '../capabilities/serve.js' import { SpaceDID } from '@storacha/capabilities/utils' @@ -51,9 +52,9 @@ function extractSpaceDID (space) { * @import * as Ucanto from '@ucanto/interface' * @import { IpfsUrlContext, Middleware } from '@web3-storage/gateway-lib' * @import { LocatorContext } from './withLocator.types.js' - * @import { AuthTokenContext } from './withAuthToken.types.js' + * @import { AuthTokenContext, Environment } from './withAuthToken.types.js' * @import { SpaceContext } from './withAuthorizedSpace.types.js' - * @import { DelegationsStorageContext } from './withDelegationsStorage.types.js' + * @import { DelegationsStorageContext, DelegationsStorageEnvironment } from './withDelegationsStorage.types.js' * @import { GatewayIdentityContext } from './withGatewayIdentity.types.js' * @import { DelegationProofsContext } from './withAuthorizedSpace.types.js' */ @@ -95,6 +96,7 @@ export function withAuthorizedSpace (handler) { ctx.authToken === null if (shouldServeLegacy) { + console.log('[withAuthorizedSpace] Using legacy path (no space)') return handler(request, env, ctx) } @@ -117,7 +119,8 @@ export function withAuthorizedSpace (handler) { // First space to successfully authorize is the one we'll use. const { space: selectedSpace, delegationProofs } = await Promise.any( spaces.map(async (space) => { - const result = await authorize(SpaceDID.from(space.toString()), ctx) + // @ts-ignore + const result = await authorize(SpaceDID.from(space), ctx, env) if (result.error) { throw result.error } @@ -168,9 +171,10 @@ export function withAuthorizedSpace (handler) { * * @param {import('@storacha/capabilities/types').SpaceDID} space * @param {AuthTokenContext & DelegationsStorageContext & GatewayIdentityContext} ctx + * @param {import('./withRateLimit.types.js').Environment} env * @returns {Promise>} */ -const authorize = async (space, ctx) => { +const authorize = async (space, ctx, env) => { // Look up delegations that might authorize us to serve the content. const relevantDelegationsResult = await ctx.delegationsStorage.find(space) if (relevantDelegationsResult.error) { @@ -197,11 +201,14 @@ const authorize = async (space, ctx) => { }) .delegate() - // Validate the invocation. + // Load validator proofs and validate the invocation + const validatorProofs = await getValidatorProofs(env) const accessResult = await access(invocation, { capability: serve.transportHttp, authority: ctx.gatewayIdentity, principal: Verifier, + proofs: validatorProofs, + resolveDIDKey, validateAuthorization: () => ok({}) }) diff --git a/src/middleware/withDelegationsStorage.types.ts b/src/middleware/withDelegationsStorage.types.ts index e6d7821..cc80669 100644 --- a/src/middleware/withDelegationsStorage.types.ts +++ b/src/middleware/withDelegationsStorage.types.ts @@ -7,6 +7,7 @@ import { SpaceDID } from '@storacha/capabilities/types' export interface DelegationsStorageEnvironment extends MiddlewareEnvironment { CONTENT_SERVE_DELEGATIONS_STORE: KVNamespace FF_DELEGATIONS_STORAGE_ENABLED: string + GATEWAY_VALIDATOR_PROOF?: string } export interface DelegationsStorageContext @@ -35,6 +36,6 @@ export interface DelegationsStorage { */ store: ( space: SpaceDID, - delegation: Ucanto.Delegation + delegation: Ucanto.Delegation, ) => Promise> } diff --git a/src/middleware/withGatewayIdentity.js b/src/middleware/withGatewayIdentity.js index d3d8ac3..af6c123 100644 --- a/src/middleware/withGatewayIdentity.js +++ b/src/middleware/withGatewayIdentity.js @@ -20,6 +20,10 @@ export function withGatewayIdentity (handler) { const gatewayIdentity = gatewaySigner.withDID( Schema.DID.from(env.GATEWAY_SERVICE_DID) ) - return handler(req, env, { ...ctx, gatewaySigner, gatewayIdentity }) + return handler(req, env, { + ...ctx, + gatewaySigner, + gatewayIdentity + }) } } diff --git a/src/middleware/withGatewayIdentity.types.ts b/src/middleware/withGatewayIdentity.types.ts index 363bb58..228c918 100644 --- a/src/middleware/withGatewayIdentity.types.ts +++ b/src/middleware/withGatewayIdentity.types.ts @@ -8,6 +8,6 @@ export interface Environment extends MiddlewareEnvironment { } export interface GatewayIdentityContext extends MiddlewareContext { - gatewaySigner: EdSigner + gatewaySigner: Ucanto.Signer gatewayIdentity: Ucanto.Signer } diff --git a/src/middleware/withRateLimit.types.ts b/src/middleware/withRateLimit.types.ts index f13888d..dd0fef2 100644 --- a/src/middleware/withRateLimit.types.ts +++ b/src/middleware/withRateLimit.types.ts @@ -6,6 +6,7 @@ export interface Environment extends MiddlewareEnvironment { RATE_LIMITER: RateLimit AUTH_TOKEN_METADATA: KVNamespace FF_RATE_LIMITER_ENABLED: string + GATEWAY_VALIDATOR_PROOF?: string } export interface TokenMetadata { diff --git a/src/middleware/withUcanInvocationHandler.js b/src/middleware/withUcanInvocationHandler.js index 5361deb..acafd44 100644 --- a/src/middleware/withUcanInvocationHandler.js +++ b/src/middleware/withUcanInvocationHandler.js @@ -22,8 +22,9 @@ export function withUcanInvocationHandler (handler) { return handler(request, env, ctx) } - const service = ctx.service ?? createService(ctx) - const server = ctx.server ?? createServer(ctx, service) + const service = + ctx.service ?? (await createService(ctx, env)) + const server = ctx.server ?? (await createServer(ctx, service, env)) const { headers, body, status } = await server.request({ body: new Uint8Array(await request.arrayBuffer()), diff --git a/src/middleware/withUcanInvocationHandler.types.ts b/src/middleware/withUcanInvocationHandler.types.ts index a313234..2aad1f4 100644 --- a/src/middleware/withUcanInvocationHandler.types.ts +++ b/src/middleware/withUcanInvocationHandler.types.ts @@ -4,6 +4,7 @@ import { DelegationsStorageContext } from './withDelegationsStorage.types.js' import { Service } from '../server/api.types.js' import * as Server from '@ucanto/server' export interface Environment extends MiddlewareEnvironment { + GATEWAY_VALIDATOR_PROOF?: string } export interface Context diff --git a/src/server/index.js b/src/server/index.js index 7b1ecae..d2360f1 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -1,5 +1,75 @@ import * as Server from '@ucanto/server' import * as CAR from '@ucanto/transport/car' +import { DIDResolutionError } from '@ucanto/validator' +import * as Proof from '@storacha/client/proof' + +/** + * Known did:web to did:key mappings for signature verification + * @type {Record<`did:${string}:${string}`, `did:key:${string}`>} + */ +const knownWebDIDs = { + // Production + 'did:web:up.storacha.network': + 'did:key:z6MkqdncRZ1wj8zxCTDUQ8CRT8NQWd63T7mZRvZUX8B7XDFi', + 'did:web:web3.storage': + 'did:key:z6MkqdncRZ1wj8zxCTDUQ8CRT8NQWd63T7mZRvZUX8B7XDFi', + 'did:web:w3s.link': + 'did:key:z6Mkha3NLZ38QiZXsUHKRHecoumtha3LnbYEL21kXYBFXvo5', + + // Staging + 'did:web:staging.up.storacha.network': + 'did:key:z6MkhcbEpJpEvNVDd3n5RurquVdqs5dPU16JDU5VZTDtFgnn', + 'did:web:staging.web3.storage': + 'did:key:z6MkhcbEpJpEvNVDd3n5RurquVdqs5dPU16JDU5VZTDtFgnn', + 'did:web:staging.w3s.link': + 'did:key:z6MkqK1d4thaCEXSGZ6EchJw3tDPhQriwynWDuR55ayATMNf' +} + +/** + * Resolves did:web DIDs to their corresponding did:key DIDs + * @param {import('@ucanto/interface').DID} did + */ +export const resolveDIDKey = async (did) => { + if (knownWebDIDs[did]) { + const didKey = /** @type {`did:key:${string}`} */ (knownWebDIDs[did]) + return Server.ok([didKey]) // Return array of did:keys + } + return Server.error(new DIDResolutionError(did)) +} + +/** + * @type {import('@ucanto/interface').Delegation[]} + */ +let cachedValidatorProofs + +/** + * Loads validator proofs from environment variable. + * These proofs allow the gateway to validate ucan/attest delegations. + * + * @param {{ GATEWAY_VALIDATOR_PROOF?: string }} env + * @returns {Promise} + */ +export const getValidatorProofs = async (env) => { + if (cachedValidatorProofs) { + return cachedValidatorProofs + } + cachedValidatorProofs = [] + if (env.GATEWAY_VALIDATOR_PROOF) { + try { + const proof = await Proof.parse(env.GATEWAY_VALIDATOR_PROOF) + const delegation = /** @type {import('@ucanto/interface').Delegation} */ ( + proof + ) + console.log( + `Gateway validator proof loaded: [issuer: ${delegation.issuer.did()}, audience: ${delegation.audience.did()}]` + ) + cachedValidatorProofs = [delegation] + } catch (error) { + console.error('Failed to parse GATEWAY_VALIDATOR_PROOF:', error) + } + } + return cachedValidatorProofs +} /** * Creates a UCAN server. @@ -7,14 +77,30 @@ import * as CAR from '@ucanto/transport/car' * @template T * @param {import('../middleware/withUcanInvocationHandler.types.js').Context} ctx * @param {import('./api.types.js').Service} service + * @param {{ GATEWAY_VALIDATOR_PROOF?: string }} env */ -export function createServer (ctx, service) { +export async function createServer (ctx, service, env) { + const proofs = await getValidatorProofs(env) + console.log('Server validator proofs loaded:', proofs.length) + if (proofs.length > 0) { + console.log('First proof details:', { + issuer: proofs[0].issuer.did(), + audience: proofs[0].audience.did(), + capabilities: proofs[0].capabilities.map((c) => ({ + can: c.can, + with: c.with + })), + cid: proofs[0].cid.toString() + }) + } return Server.create({ - id: ctx.gatewaySigner, + id: ctx.gatewaySigner.withDID(ctx.gatewayIdentity.did()), codec: CAR.inbound, service, - catch: err => console.error(err), + catch: (err) => console.error(err), // TODO: wire into revocations - validateAuthorization: () => ({ ok: {} }) + validateAuthorization: () => ({ ok: {} }), + resolveDIDKey, + proofs }) } diff --git a/src/server/service.js b/src/server/service.js index bb3ebab..4a14b52 100644 --- a/src/server/service.js +++ b/src/server/service.js @@ -6,22 +6,27 @@ import { extractContentServeDelegations } from './utils.js' import { claim, Schema } from '@ucanto/validator' import * as UcantoServer from '@ucanto/server' import { ok } from '@ucanto/client' +import { getValidatorProofs } from './index.js' /** * @template T * @param {import('../middleware/withUcanInvocationHandler.types.js').Context} ctx + * @param {import('../middleware/withUcanInvocationHandler.types.js').Environment} env * @returns {import('./api.types.js').Service} */ -export function createService (ctx) { +export function createService (ctx, env) { return { access: { delegate: UcantoServer.provideAdvanced({ capability: AccessCapabilities.delegate, - audience: Schema.did({ method: 'web' }), + audience: Schema.did({ method: 'web' }).or( + Schema.did({ method: 'key' }) + ), handler: async ({ capability, invocation, context }) => { - const result = extractContentServeDelegations( + console.log('extracting delegations: ', capability) + const result = await extractContentServeDelegations( capability, - invocation.proofs + invocation ) if (result.error) { console.error('error while extracting delegation', result.error) @@ -29,25 +34,30 @@ export function createService (ctx) { } const delegations = result.ok - const validationResults = await Promise.all( - delegations.map(async (delegation) => { - const validationResult = await claim( - SpaceCapabilities.contentServe, - [delegation], - { - ...context, - authority: ctx.gatewayIdentity - } - ) - if (validationResult.error) { - console.error( - 'error while validating delegation', - validationResult.error - ) - return validationResult - } + console.log('executing claim for delegations: ', delegations) + const validatorProofs = await getValidatorProofs(env) + console.log('validatorProofs: ', validatorProofs) + const validationResult = await claim( + SpaceCapabilities.contentServe, + delegations, + { + ...context, + authority: ctx.gatewayIdentity, + proofs: [...validatorProofs] + } + ) + if (validationResult.error) { + console.error( + 'error while validating delegation', + validationResult.error + ) + return validationResult + } - const space = capability.with + const space = capability.with + + const validationResults = await Promise.all( + delegations.map((delegation) => { return ctx.delegationsStorage.store(space, delegation) }) ) diff --git a/src/server/utils.js b/src/server/utils.js index 225b352..7fcd3a0 100644 --- a/src/server/utils.js +++ b/src/server/utils.js @@ -1,49 +1,73 @@ import { Space as SpaceCapabilities } from '@storacha/capabilities' import { InvalidDelegation } from '../middleware/withDelegationsStorage.js' +import { Delegation } from '@ucanto/core' /** * Checks if the space/content/serve/* delegation is for the gateway and it is not expired. * * @param {import('@ucanto/interface').InferInvokedCapability} capability - The capability to validate - * @param {import('@ucanto/interface').Proof[]} proofs - The proofs to validate + * @param {import('@ucanto/interface').Invocation} invocation - The invocation containing attached blocks */ -export const extractContentServeDelegations = (capability, proofs) => { - const nbDelegations = new Set(Object.values(capability.nb.delegations)) - if (nbDelegations.size !== 1) { - return { - error: new InvalidDelegation( - 'nb.delegations has more than one delegation' - ) - } +export const extractContentServeDelegations = async ( + capability, + invocation +) => { + /** @type {Map} */ + const blocks = new Map() + for (const block of invocation.iterateIPLDBlocks()) { + blocks.set(block.cid.toString(), block) } - const delegations = [] - for (const delegationLink of nbDelegations) { - const proofDelegations = proofs.flatMap((proof) => - 'capabilities' in proof ? [proof] : [] - ) - const delegationProof = proofDelegations.find((p) => - delegationLink.equals(p.cid) - ) - if (!delegationProof) { - return { - error: new InvalidDelegation( - `delegation not found in proofs: ${delegationLink}` - ) + + const delegations = await Promise.all( + Object.values(capability.nb.delegations).map(async (cid) => { + const block = blocks.get(cid.toString()) + if (!block) { + throw new Error(`Block not found for delegation CID: ${cid}`) } - } - if ( - !delegationProof.capabilities.some( - (c) => c.can === SpaceCapabilities.contentServe.can - ) - ) { - return { - error: new InvalidDelegation( - `delegation does not contain ${SpaceCapabilities.contentServe.can} capability` - ) + // Try to extract delegation from CAR archive + try { + const delegation = await Delegation.extract(block.bytes) + if (delegation.error) { + throw delegation.error + } + return delegation.ok + } catch (error) { + // Fallback: treat as raw delegation block + const link = cid.link() + const cidv1 = link.version === 0 ? link.toV1() : link + return Delegation.create({ + root: { + cid: /** @type {import('@ucanto/interface').UCANLink} */ (cidv1), + bytes: block.bytes + }, + blocks + }) } + }) + ) + + const validDelegations = delegations + .map((delegation) => { + // check for each capability if it is a content serve capability + if (delegation.capabilities.length === 0) { + return false + } + const result = delegation.capabilities.some((c) => { + return SpaceCapabilities.contentServe.match({ + capability: /** @type {any} */ (c), + delegation + }).ok + }) + return result + }) + .filter((r) => r) + + if (validDelegations.length === 0) { + return { + error: new InvalidDelegation('no valid delegations found') } - delegations.push(delegationProof) } + return { ok: delegations } } diff --git a/wrangler.toml b/wrangler.toml index 60803d2..ba9ae61 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -72,6 +72,7 @@ CONTENT_CLAIMS_SERVICE_URL = "https://claims.web3.storage" CARPARK_PUBLIC_BUCKET_URL = "https://carpark-prod-0.r2.w3s.link" UPLOAD_API_URL = "https://up.web3.storage" INDEXING_SERVICE_URL = "https://indexer.storacha.network/" +GATEWAY_VALIDATOR_PROOF = "mAYIEAPQCOqJlcm9vdHOB2CpYJQABcRIgYOVdOrpLxbw0mELO22krjEVICp5cju4nVChUCL8+i/1ndmVyc2lvbgHdAQFxEiCUjD+aZlOcJxbn3UlM1dqeSYs09dyPrMvVKPmC+TSaoadhc1hE7aEDQPhDJ+yO05lTqYJndtPY9d2WXGtyj90eoL0MBeKylYKMQDnSMBkMAv8XMX+OEZd7QrhvzAktsXMEKY+wPQAbpQRhdmUwLjkuMWNhdHSBomNjYW5rdWNhbi9hdHRlc3Rkd2l0aHBkaWQ6d2ViOnczcy5saW5rY2F1ZFgZnRp3ZWI6dXAuc3RvcmFjaGEubmV0d29ya2NleHD2Y2lzc06dGndlYjp3M3MubGlua2NwcmaAWQFxEiBg5V06ukvFvDSYQs7baSuMRUgKnlyO7idUKFQIvz6L/aFqdWNhbkAwLjkuMdgqWCUAAXESIJSMP5pmU5wnFufdSUzV2p5JizT13I+sy9Uo+YL5NJqh" [env.production.observability] enabled = true @@ -115,7 +116,7 @@ CONTENT_CLAIMS_SERVICE_URL = "https://staging.claims.web3.storage" UPLOAD_API_URL = "https://staging.up.web3.storage" CARPARK_PUBLIC_BUCKET_URL = "https://carpark-staging-0.r2.w3s.link" INDEXING_SERVICE_URL = "https://staging.indexer.storacha.network/" - +GATEWAY_VALIDATOR_PROOF = "mAYIEAI0DOqJlcm9vdHOB2CpYJQABcRIg5a/pcyEeJn5snQZHm+wVBzeFbY8RTlfwETn+nMMiCqlndmVyc2lvbgH2AQFxEiD8LRCZwMMfTVlGtNX85n0aVxjp54oE0/G/WTG/dsOOA6dhc1hE7aEDQCEy4qAv4dybXYh/iipwdOLf4DlYjZGFopGvvfDZbVq6Q4MIY5PY9XXHP9D6ELs6qjcvSLfP/nbew/IWbG55RAJhdmUwLjkuMWNhdHSBomNjYW5rdWNhbi9hdHRlc3Rkd2l0aHgYZGlkOndlYjpzdGFnaW5nLnczcy5saW5rY2F1ZFghnRp3ZWI6c3RhZ2luZy51cC5zdG9yYWNoYS5uZXR3b3JrY2V4cPZjaXNzVp0ad2ViOnN0YWdpbmcudzNzLmxpbmtjcHJmgFkBcRIg5a/pcyEeJn5snQZHm+wVBzeFbY8RTlfwETn+nMMiCqmhanVjYW5AMC45LjHYKlglAAFxEiD8LRCZwMMfTVlGtNX85n0aVxjp54oE0/G/WTG/dsOOAw" # Test! [env.test] @@ -166,21 +167,24 @@ account_id = "fffa4b4363a7e5250af8357087263b3a" # r2_buckets = [ # { binding = "CARPARK", bucket_name = "carpark-fforbeck-0", preview_bucket_name = "carpark-fforbeck-preview-0" } # ] -# r2_buckets = [ -# { binding = "CARPARK", bucket_name = "carpark-staging-0" } -# ] +#r2_buckets = [ +# { binding = "CARPARK", bucket_name = "carpark-prod-0", preview_bucket_name = "carpark-prod-0" } +#] +#kv_namespaces = [ +# { binding = "AUTH_TOKEN_METADATA", id = "b618bb05deb8493f944ef4a0f538030c" }, +# { binding = "CONTENT_SERVE_DELEGATIONS_STORE", id = "26cc47fec09749bb9ee42bc6407f9a9d" }, +# { binding = "DAGPB_CONTENT_CACHE", id = "3f0c253b90fc48c1b384f1563ede54f9" } +#] +# Copied from STAGING env r2_buckets = [ - { binding = "CARPARK", bucket_name = "carpark-staging-0" } + { binding = "CARPARK", bucket_name = "carpark-staging-0", preview_bucket_name = "carpark-staging-0" } ] kv_namespaces = [ - { binding = "AUTH_TOKEN_METADATA", id = "b618bb05deb8493f944ef4a0f538030c" }, - { binding = "CONTENT_SERVE_DELEGATIONS_STORE", id = "99ae45f8b5b3478a9df09302c27e81a3" }, - { binding = "DAGPB_CONTENT_CACHE", id = "3f0c253b90fc48c1b384f1563ede54f9" } + { binding = "AUTH_TOKEN_METADATA", id = "b618bb05deb8493f944ef4a0f538030c", preview_id = "6a546b5fc21a423eb4ea07db2d611a91" }, + { binding = "CONTENT_SERVE_DELEGATIONS_STORE", id = "99ae45f8b5b3478a9df09302c27e81a3", preview_id = "ec5c429f8b1849a68d73dee7447b4e30" }, + { binding = "DAGPB_CONTENT_CACHE", id = "c70a74363e7a4f06ad39fa3022aab7c7", preview_id = "fcea72d8d8694b5c831736e1317e9208" } ] -[env.fforbeck.observability.logs] -enabled = true - [env.fforbeck.vars] DEBUG = "true" FF_RATE_LIMITER_ENABLED = "false" @@ -189,24 +193,18 @@ FF_EGRESS_TRACKER_ROLLOUT_PERCENTAGE = "100" FF_TELEMETRY_ENABLED = "true" FF_DELEGATIONS_STORAGE_ENABLED = "true" FF_RAMP_UP_PROBABILITY = "100" -FF_DAGPB_CONTENT_CACHE_TTL_SECONDS = 300 +FF_DAGPB_CONTENT_CACHE_TTL_SECONDS = 0 FF_DAGPB_CONTENT_CACHE_MAX_SIZE_MB = 2 -FF_DAGPB_CONTENT_CACHE_ENABLED = "true" +FF_DAGPB_CONTENT_CACHE_ENABLED = "false" TELEMETRY_RATIO = 1.0 -### staging CONTENT_CLAIMS_SERVICE_URL = "https://staging.claims.web3.storage" CARPARK_PUBLIC_BUCKET_URL = "https://carpark-staging-0.r2.w3s.link" GATEWAY_SERVICE_DID = "did:web:staging.w3s.link" UPLOAD_SERVICE_DID = "did:web:staging.up.storacha.network" UPLOAD_API_URL = "https://staging.up.storacha.network" INDEXING_SERVICE_URL = "https://staging.indexer.storacha.network/" -### prod -#CONTENT_CLAIMS_SERVICE_URL = "https://claims.web3.storage" -#CARPARK_PUBLIC_BUCKET_URL = "https://carpark-prod-0.r2.w3s.link" -#GATEWAY_SERVICE_DID = "did:web:w3s.link" -#UPLOAD_SERVICE_DID = "did:web:web3.storage" -#UPLOAD_API_URL = "https://up.web3.storage" -#INDEXING_SERVICE_URL = "https://indexer.storacha.network/" +MAX_SHARDS = "825" +GATEWAY_VALIDATOR_PROOF = "mAYIEAI0DOqJlcm9vdHOB2CpYJQABcRIg5a/pcyEeJn5snQZHm+wVBzeFbY8RTlfwETn+nMMiCqlndmVyc2lvbgH2AQFxEiD8LRCZwMMfTVlGtNX85n0aVxjp54oE0/G/WTG/dsOOA6dhc1hE7aEDQCEy4qAv4dybXYh/iipwdOLf4DlYjZGFopGvvfDZbVq6Q4MIY5PY9XXHP9D6ELs6qjcvSLfP/nbew/IWbG55RAJhdmUwLjkuMWNhdHSBomNjYW5rdWNhbi9hdHRlc3Rkd2l0aHgYZGlkOndlYjpzdGFnaW5nLnczcy5saW5rY2F1ZFghnRp3ZWI6c3RhZ2luZy51cC5zdG9yYWNoYS5uZXR3b3JrY2V4cPZjaXNzVp0ad2ViOnN0YWdpbmcudzNzLmxpbmtjcHJmgFkBcRIg5a/pcyEeJn5snQZHm+wVBzeFbY8RTlfwETn+nMMiCqmhanVjYW5AMC45LjHYKlglAAFxEiD8LRCZwMMfTVlGtNX85n0aVxjp54oE0/G/WTG/dsOOAw" [[env.fforbeck.unsafe.bindings]] name = "RATE_LIMITER" @@ -218,6 +216,13 @@ simple = { limit = 5, period = 60 } queue = "egress-tracking-queue-staging" binding = "EGRESS_QUEUE" +[env.fforbeck.observability] +[env.fforbeck.observability.logs] +enabled = true +head_sampling_rate = 1 +invocation_logs = true +persist = false + [env.hannahhoward] name = "freeway-hannahhoward" workers_dev = true