diff --git a/internal/atproto/lexicon/social/coves/actor/profile.json b/internal/atproto/lexicon/social/coves/actor/profile.json index 90da1ca..4df7d50 100644 --- a/internal/atproto/lexicon/social/coves/actor/profile.json +++ b/internal/atproto/lexicon/social/coves/actor/profile.json @@ -46,20 +46,13 @@ "accept": ["image/png", "image/jpeg", "image/webp"], "maxSize": 2000000 }, - "verified": { - "type": "boolean", - "default": false, - "description": "Whether the user has completed phone verification" - }, - "verifiedAt": { - "type": "string", - "format": "datetime", - "description": "When the user was verified" - }, - "verificationExpiresAt": { - "type": "string", - "format": "datetime", - "description": "When verification expires" + "verifications": { + "type": "array", + "description": "Cryptographically signed verifications from trusted services", + "items": { + "type": "ref", + "ref": "#verification" + } }, "federatedFrom": { "type": "string", @@ -217,6 +210,41 @@ "description": "Human-readable location name" } } + }, + "verification": { + "type": "object", + "description": "A cryptographically signed verification from a trusted service", + "required": ["type", "verifiedBy", "verifiedAt", "expiresAt", "signature"], + "properties": { + "type": { + "type": "string", + "knownValues": ["phone", "email", "domain", "government_id"], + "description": "Type of verification performed" + }, + "verifiedBy": { + "type": "string", + "format": "did", + "description": "DID of the service that performed verification (e.g., did:web:coves.social)" + }, + "verifiedAt": { + "type": "string", + "format": "datetime", + "description": "When the verification was completed" + }, + "expiresAt": { + "type": "string", + "format": "datetime", + "description": "When this verification expires and requires renewal" + }, + "signature": { + "type": "string", + "description": "Base64-encoded signature over verification data (type + verifiedBy + verifiedAt + expiresAt + subject DID)" + }, + "metadata": { + "type": "object", + "description": "Optional verification-specific metadata (e.g., phone country code, domain name)" + } + } } } } \ No newline at end of file diff --git a/internal/atproto/lexicon/social/coves/verification/getStatus.json b/internal/atproto/lexicon/social/coves/verification/getStatus.json new file mode 100644 index 0000000..b92c041 --- /dev/null +++ b/internal/atproto/lexicon/social/coves/verification/getStatus.json @@ -0,0 +1,41 @@ +{ + "lexicon": 1, + "id": "social.coves.verification.getStatus", + "defs": { + "main": { + "type": "query", + "description": "Get phone verification status for the authenticated user.", + "parameters": { + "type": "params", + "properties": {} + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["hasVerifiedPhone"], + "properties": { + "hasVerifiedPhone": { + "type": "boolean", + "description": "Whether the user has a verified phone" + }, + "verifiedAt": { + "type": "string", + "format": "datetime", + "description": "When phone was verified" + }, + "expiresAt": { + "type": "string", + "format": "datetime", + "description": "When verification expires" + }, + "needsRenewal": { + "type": "boolean", + "description": "Whether verification is expiring soon (within 30 days)" + } + } + } + } + } + } +} diff --git a/internal/atproto/lexicon/social/coves/verification/requestPhone.json b/internal/atproto/lexicon/social/coves/verification/requestPhone.json new file mode 100644 index 0000000..9fdb379 --- /dev/null +++ b/internal/atproto/lexicon/social/coves/verification/requestPhone.json @@ -0,0 +1,59 @@ +{ + "lexicon": 1, + "id": "social.coves.verification.requestPhone", + "defs": { + "main": { + "type": "procedure", + "description": "Request a phone verification OTP code. Rate limited to prevent abuse.", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["phoneNumber"], + "properties": { + "phoneNumber": { + "type": "string", + "description": "Phone number in E.164 format (e.g., +14155552671)" + } + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["requestId", "expiresAt"], + "properties": { + "requestId": { + "type": "string", + "description": "Unique identifier for this verification request" + }, + "expiresAt": { + "type": "string", + "format": "datetime", + "description": "When the OTP code expires" + } + } + } + }, + "errors": [ + { + "name": "InvalidPhoneNumber", + "description": "Phone number format is invalid" + }, + { + "name": "PhoneAlreadyVerified", + "description": "This phone number is already verified by another account" + }, + { + "name": "RateLimitExceeded", + "description": "Too many verification requests. Please try again later." + }, + { + "name": "SMSDeliveryFailed", + "description": "Failed to send SMS to the provided number" + } + ] + } + } +} diff --git a/internal/atproto/lexicon/social/coves/verification/verifyPhone.json b/internal/atproto/lexicon/social/coves/verification/verifyPhone.json new file mode 100644 index 0000000..e33e9a7 --- /dev/null +++ b/internal/atproto/lexicon/social/coves/verification/verifyPhone.json @@ -0,0 +1,72 @@ +{ + "lexicon": 1, + "id": "social.coves.verification.verifyPhone", + "defs": { + "main": { + "type": "procedure", + "description": "Verify phone number with OTP code. On success, writes signed verification to user's PDS profile.", + "input": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["requestId", "code"], + "properties": { + "requestId": { + "type": "string", + "description": "Request ID from requestPhone call" + }, + "code": { + "type": "string", + "description": "6-digit OTP code received via SMS" + } + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["verified", "verifiedAt", "expiresAt"], + "properties": { + "verified": { + "type": "boolean", + "description": "Whether verification was successful" + }, + "verifiedAt": { + "type": "string", + "format": "datetime", + "description": "When the verification completed" + }, + "expiresAt": { + "type": "string", + "format": "datetime", + "description": "When verification expires (1 year from verifiedAt)" + } + } + } + }, + "errors": [ + { + "name": "InvalidCode", + "description": "The provided OTP code is incorrect" + }, + { + "name": "CodeExpired", + "description": "The OTP code has expired. Request a new one." + }, + { + "name": "RequestNotFound", + "description": "Invalid or expired request ID" + }, + { + "name": "TooManyAttempts", + "description": "Too many failed verification attempts. Request a new code." + }, + { + "name": "PDSWriteFailed", + "description": "Failed to write verification to user's PDS profile" + } + ] + } + } +}