+1
-1
.env.example
+1
-1
.env.example
+3
-13
.github/workflows/docker-image.yml
+3
-13
.github/workflows/docker-image.yml
······# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.···# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.···
-10
Caddyfile
-10
Caddyfile
-10
Caddyfile.postgres
-10
Caddyfile.postgres
+1
-37
Makefile
+1
-37
Makefile
······-GOOS=$(OS) GOARCH=$(ARCH) go build -ldflags "-X main.Version=$(VERSION)" -o $(OUTPUT) ./cmd/cocoon && \···
+7
-181
README.md
+7
-181
README.md
···-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.+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.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)-By default, Cocoon uses SQLite which requires no additional setup. For production deployments with higher traffic, you can use PostgreSQL:-> **Note**: When using PostgreSQL, database backups to S3 are not handled by Cocoon. Use `pg_dump` or your database provider's backup solution instead.-Cocoon supports S3-compatible storage for both database backups (SQLite only) and blob storage (images, videos, etc.):······+- [x] `com.atproto.repo.importRepo` (Works "okay". You still have to handle PLC operations on your own when migrating. Use with extreme caution.)-- [x] `com.atproto.repo.listMissingBlobs` (Not actually functional, but will return a response as if no blobs were missing)
+43
-66
cmd/cocoon/main.go
+43
-66
cmd/cocoon/main.go
··················
-56
create-initial-invite.sh
-56
create-initial-invite.sh
···-echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"-echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
-158
docker-compose.postgres.yaml
-158
docker-compose.postgres.yaml
···-COCOON_DATABASE_URL: postgres://cocoon:${POSTGRES_PASSWORD}@postgres:5432/cocoon?sslmode=disable-COCOON_DATABASE_URL: postgres://cocoon:${POSTGRES_PASSWORD}@postgres:5432/cocoon?sslmode=disable
-129
docker-compose.yaml
-129
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
···
+1
-3
models/models.go
+1
-3
models/models.go
······
+28
-44
oauth/client/manager.go
+28
-44
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) {·········
+15
-31
plc/client.go
+15
-31
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
···
-24
server/handle_identity_get_recommended_did_credentials.go
-24
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
···
+1
-1
server/handle_import_repo.go
+1
-1
server/handle_import_repo.go
+2
-15
server/handle_proxy.go
+2
-15
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())
-21
server/handle_repo_list_missing_blobs.go
-21
server/handle_repo_list_missing_blobs.go
···
+35
-45
server/handle_server_create_account.go
+35
-45
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 != signupDid {+if did, err := s.passport.ResolveHandle(e.Request().Context(), request.Handle); err == nil && did != "" {···s.logger.Error("error looking up email in db", "endpoint", "com.atproto.server.createAccount", "error", err)···
+1
-6
server/handle_sync_get_blob.go
+1
-6
server/handle_sync_get_blob.go
···
+11
-31
server/handle_sync_subscribe_repos.go
+11
-31
server/handle_sync_subscribe_repos.go
······conn, err := websocket.Upgrade(e.Response().Writer, e.Request(), e.Response().Header(), 1<<10, 1<<10)······
-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))
+9
-75
server/server.go
+9
-75
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)s.echo.POST("/xrpc/com.atproto.server.createInviteCode", s.handleCreateInviteCode, s.handleAdminMiddleware)···-s.logger.Info("skipping S3 backup - PostgreSQL backups should be handled externally (pg_dump, managed database backups, etc.)")
-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))