+1
-1
.env.example
+1
-1
.env.example
+3
-1
.github/workflows/docker-image.yml
+3
-1
.github/workflows/docker-image.yml
+10
Caddyfile
+10
Caddyfile
+137
-6
README.md
+137
-6
README.md
···-You should not use this PDS. You should not rely on this code as a reference for a PDS implementation. You should not trust this code. Using this PDS implementation may result in data loss, corruption, etc.+I migrated and have been running my main account on this PDS for months now without issue, however, I am still not responsible if things go awry, particularly during account migration. Please use caution.Cocoon is a PDS implementation in Go. It is highly experimental, and is not ready for any production use.+- **init-keys**: Automatically generates cryptographic keys (rotation key and JWK) on first run+- **create-invite**: Automatically creates an initial invite code after Cocoon starts (first run only)······-- [x] `com.atproto.repo.importRepo` (Works "okay". You still have to handle PLC operations on your own when migrating. Use with extreme caution.)
+26
-39
cmd/cocoon/main.go
+26
-39
cmd/cocoon/main.go
···
+56
create-initial-invite.sh
+56
create-initial-invite.sh
···+echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"+echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
+125
docker-compose.yaml
+125
docker-compose.yaml
···
+1
-1
identity/types.go
+1
-1
identity/types.go
···
+34
init-keys.sh
+34
init-keys.sh
···
+6
internal/db/db.go
+6
internal/db/db.go
···
+16
internal/helpers/helpers.go
+16
internal/helpers/helpers.go
···
+2
models/models.go
+2
models/models.go
+44
-28
oauth/client/manager.go
+44
-28
oauth/client/manager.go
······jwksCache := cache.NewCache[string, jwk.Key]().WithLRU().WithMaxKeys(500).WithTTL(5 * time.Minute)-metadataCache := cache.NewCache[string, Metadata]().WithLRU().WithMaxKeys(500).WithTTL(5 * time.Minute)+metadataCache := cache.NewCache[string, *Metadata]().WithLRU().WithMaxKeys(500).WithTTL(5 * time.Minute)···-// TODO: this is kinda bad but whatever for now. there could obviously be more than one jwk, and we need to+// TODO: this is kinda bad but whatever for now. there could obviously be more than one jwk, and we need to···func (cm *Manager) getClientMetadata(ctx context.Context, clientId string) (*Metadata, error) {·········
+31
-15
plc/client.go
+31
-15
plc/client.go
···func (c *Client) CreateDID(sigkey *atcrypto.PrivateKeyK256, recovery string, handle string) (string, *Operation, error) {+func (c *Client) CreateDidCredentials(sigkey *atcrypto.PrivateKeyK256, recovery string, handle string) (*DidCredentials, error) {······
+8
plc/types.go
+8
plc/types.go
···
+1
server/handle_account.go
+1
server/handle_account.go
+26
server/handle_identity_get_recommended_did_credentials.go
+26
server/handle_identity_get_recommended_did_credentials.go
···
+29
server/handle_identity_request_plc_operation.go
+29
server/handle_identity_request_plc_operation.go
···+if err := s.db.Exec("UPDATE repos SET plc_operation_code = ?, plc_operation_code_expires_at = ? WHERE did = ?", nil, code, eat, urepo.Repo.Did).Error; err != nil {
+103
server/handle_identity_sign_plc_operation.go
+103
server/handle_identity_sign_plc_operation.go
···+if err := s.db.Exec("UPDATE repos SET plc_operation_code = NULL, plc_operation_code_expires_at = NULL WHERE did = ?", nil, repo.Repo.Did).Error; err != nil {
+87
server/handle_identity_submit_plc_operation.go
+87
server/handle_identity_submit_plc_operation.go
···
+9
-8
server/handle_import_repo.go
+9
-8
server/handle_import_repo.go
··················
+15
-2
server/handle_proxy.go
+15
-2
server/handle_proxy.go
···
+35
server/handle_proxy_get_feed.go
+35
server/handle_proxy_get_feed.go
···+feedRecord, err := atproto.RepoGetRecord(e.Request().Context(), &appViewClient, "", feedUri.Collection().String(), feedUri.Authority().String(), feedUri.RecordKey().String())
+3
-1
server/handle_repo_apply_writes.go
+3
-1
server/handle_repo_apply_writes.go
······
+3
-1
server/handle_repo_create_record.go
+3
-1
server/handle_repo_create_record.go
······
+3
-1
server/handle_repo_delete_record.go
+3
-1
server/handle_repo_delete_record.go
······
+3
-1
server/handle_repo_put_record.go
+3
-1
server/handle_repo_put_record.go
······
+46
-15
server/handle_server_check_account_status.go
+46
-15
server/handle_server_check_account_status.go
············-if err := s.db.Raw("SELECT COUNT(*) AS ct FROM blocks WHERE did = ?", nil, urepo.Repo.Did).Scan(&blockCtResp).Error; err != nil {+if err := s.db.Raw("SELECT COUNT(*) AS ct FROM blocks WHERE did = ?", nil, urepo.Repo.Did).Scan(&blockCtResp).Error; err != nil {+if err := s.db.Raw("SELECT COUNT(*) AS ct FROM records WHERE did = ?", nil, urepo.Repo.Did).Scan(&recCtResp).Error; err != nil {-if err := s.db.Raw("SELECT COUNT(*) AS ct FROM records WHERE did = ?", nil, urepo.Repo.Did).Scan(&recCtResp).Error; err != nil {+if err := s.db.Raw("SELECT COUNT(*) AS ct FROM blobs WHERE did = ?", nil, urepo.Repo.Did).Scan(&blobCtResp).Error; err != nil {-if err := s.db.Raw("SELECT COUNT(*) AS ct FROM blobs WHERE did = ?", nil, urepo.Repo.Did).Scan(&blobCtResp).Error; err != nil {
+45
-35
server/handle_server_create_account.go
+45
-35
server/handle_server_create_account.go
······s.logger.Error("error receiving request", "endpoint", "com.atproto.server.createAccount", "error", err)···+token := strings.TrimSpace(strings.Replace(e.Request().Header.Get("authorization"), "Bearer ", "", 1))+authDid, err := s.validateServiceAuth(e.Request().Context(), token, "com.atproto.server.createAccount")+s.logger.Warn("error validating authorization token", "endpoint", "com.atproto.server.createAccount", "error", err)s.logger.Error("error looking up handle in db", "endpoint", "com.atproto.server.createAccount", "error", err)-if did, err := s.passport.ResolveHandle(e.Request().Context(), request.Handle); err == nil && did != "" {+if did, err := s.passport.ResolveHandle(e.Request().Context(), request.Handle); err == nil && did != signupDid {···s.logger.Error("error looking up email in db", "endpoint", "com.atproto.server.createAccount", "error", err)···
+3
-1
server/handle_sync_get_record.go
+3
-1
server/handle_sync_get_record.go
······
+19
server/mail.go
+19
server/mail.go
···+s.mail.Plain().Set(fmt.Sprintf("Hello %s. Your PLC operation code is %s. This code will expire in ten minutes.", handle, code))
+19
-16
server/repo.go
+19
-16
server/repo.go
···-func (rm *RepoMan) applyWrites(urepo models.Repo, writes []Op, swapCommit *string) ([]ApplyWriteResult, error) {+func (rm *RepoMan) applyWrites(ctx context.Context, urepo models.Repo, writes []Op, swapCommit *string) ([]ApplyWriteResult, error) {······························-func (rm *RepoMan) getRecordProof(urepo models.Repo, collection, rkey string) (cid.Cid, []blocks.Block, error) {+func (rm *RepoMan) getRecordProof(ctx context.Context, urepo models.Repo, collection, rkey string) (cid.Cid, []blocks.Block, error) {···
+5
-1
server/server.go
+5
-1
server/server.go
······s.echo.GET("/xrpc/com.atproto.server.getSession", s.handleGetSession, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)s.echo.POST("/xrpc/com.atproto.server.refreshSession", s.handleRefreshSession, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)s.echo.POST("/xrpc/com.atproto.server.deleteSession", s.handleDeleteSession, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)+s.echo.GET("/xrpc/com.atproto.identity.getRecommendedDidCredentials", s.handleGetRecommendedDidCredentials, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)s.echo.POST("/xrpc/com.atproto.identity.updateHandle", s.handleIdentityUpdateHandle, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)+s.echo.POST("/xrpc/com.atproto.identity.requestPlcOperationSignature", s.handleIdentityRequestPlcOperationSignature, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)+s.echo.POST("/xrpc/com.atproto.identity.signPlcOperation", s.handleSignPlcOperation, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)+s.echo.POST("/xrpc/com.atproto.identity.submitPlcOperation", s.handleSubmitPlcOperation, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)s.echo.POST("/xrpc/com.atproto.server.confirmEmail", s.handleServerConfirmEmail, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)s.echo.POST("/xrpc/com.atproto.server.requestEmailConfirmation", s.handleServerRequestEmailConfirmation, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)s.echo.POST("/xrpc/com.atproto.server.requestPasswordReset", s.handleServerRequestPasswordReset) // AUTH NOT REQUIRED FOR THIS ONE···s.echo.GET("/xrpc/app.bsky.actor.getPreferences", s.handleActorGetPreferences, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)s.echo.POST("/xrpc/app.bsky.actor.putPreferences", s.handleActorPutPreferences, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)+s.echo.GET("/xrpc/app.bsky.feed.getFeed", s.handleProxyBskyFeedGetFeed, s.handleLegacySessionMiddleware, s.handleOauthSessionMiddleware)
+91
server/service_auth.go
+91
server/service_auth.go
···+func (m *ES256KSigningMethod) Verify(signingString string, signature string, key interface{}) error {+func (s *Server) validateServiceAuth(ctx context.Context, rawToken string, nsid string) (string, error) {+parsedToken, err := jwt.ParseWithClaims(token, jwt.MapClaims{}, func(token *jwt.Token) (interface{}, error) {+verificationMethods := make([]atproto_identity.DocVerificationMethod, len(didDoc.VerificationMethods))