This commit is contained in:
parent
65b1d40da2
commit
4b60194897
15 changed files with 333 additions and 126 deletions
19
cmd/main.go
19
cmd/main.go
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/ilyakaznacheev/cleanenv"
|
"github.com/ilyakaznacheev/cleanenv"
|
||||||
"github.com/royalcat/konfa-server/pkg/uuid"
|
"github.com/royalcat/konfa-server/pkg/uuid"
|
||||||
|
"github.com/royalcat/konfa-server/src/auth"
|
||||||
"github.com/royalcat/konfa-server/src/konfa"
|
"github.com/royalcat/konfa-server/src/konfa"
|
||||||
"github.com/royalcat/konfa-server/src/proto"
|
"github.com/royalcat/konfa-server/src/proto"
|
||||||
chatv1 "github.com/royalcat/konfa-server/src/proto/konfa/chat/v1"
|
chatv1 "github.com/royalcat/konfa-server/src/proto/konfa/chat/v1"
|
||||||
|
@ -36,7 +37,19 @@ func main() {
|
||||||
|
|
||||||
srv := konfa.NewService(db, dbpool)
|
srv := konfa.NewService(db, dbpool)
|
||||||
|
|
||||||
grpcServer := grpc.NewServer(grpc.UnaryInterceptor(proto.Authenticate))
|
authen, err := auth.NewAuthenticator(ctx, db, auth.AuthenticatorConfig{
|
||||||
|
Issuer: "https://sso.konfach.ru/realms/konfach",
|
||||||
|
ClientID: "konfa",
|
||||||
|
ClientSecret: "UqeaMowRXcGULkAepr0EAEUfE82OjY72",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
grpcServer := grpc.NewServer(
|
||||||
|
grpc.UnaryInterceptor(authen.UnaryAuthenticate),
|
||||||
|
grpc.StreamInterceptor(authen.StreamAuthenticate),
|
||||||
|
)
|
||||||
chatv1.RegisterChatServiceServer(grpcServer, proto.NewChatService(srv))
|
chatv1.RegisterChatServiceServer(grpcServer, proto.NewChatService(srv))
|
||||||
serverv1.RegisterServerServiceServer(grpcServer, proto.NewServerService(srv))
|
serverv1.RegisterServerServiceServer(grpcServer, proto.NewServerService(srv))
|
||||||
|
|
||||||
|
@ -80,7 +93,7 @@ func createKonfach(ctx context.Context, srv *konfa.Service) (uuid.UUID, uuid.UUI
|
||||||
|
|
||||||
var chanID uuid.UUID
|
var chanID uuid.UUID
|
||||||
|
|
||||||
channels, err := srv.ListChannelsOnServer(ctx, serverID)
|
channels, err := srv.ListTextChannelsOnServer(ctx, serverID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return uuid.Nil, uuid.Nil, err
|
return uuid.Nil, uuid.Nil, err
|
||||||
}
|
}
|
||||||
|
@ -90,7 +103,7 @@ func createKonfach(ctx context.Context, srv *konfa.Service) (uuid.UUID, uuid.UUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if chanID == uuid.Nil {
|
if chanID == uuid.Nil {
|
||||||
chanID, err = srv.CreateChannel(ctx, serverID, "general")
|
chanID, err = srv.CreateTextChannel(ctx, serverID, "general")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return uuid.Nil, uuid.Nil, fmt.Errorf("failed to create channel: %w", err)
|
return uuid.Nil, uuid.Nil, fmt.Errorf("failed to create channel: %w", err)
|
||||||
}
|
}
|
||||||
|
|
13
go.mod
13
go.mod
|
@ -24,9 +24,12 @@ require (
|
||||||
github.com/BurntSushi/toml v1.2.1 // indirect
|
github.com/BurntSushi/toml v1.2.1 // indirect
|
||||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||||
github.com/buger/jsonparser v1.1.1 // indirect
|
github.com/buger/jsonparser v1.1.1 // indirect
|
||||||
|
github.com/coreos/go-oidc/v3 v3.11.0 // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
@ -42,13 +45,19 @@ require (
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mfridman/interpolate v0.0.2 // indirect
|
github.com/mfridman/interpolate v0.0.2 // indirect
|
||||||
|
github.com/muhlemmer/gu v0.3.1 // indirect
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect
|
github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect
|
||||||
github.com/sethvargo/go-retry v0.3.0 // indirect
|
github.com/sethvargo/go-retry v0.3.0 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
||||||
github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 // indirect
|
github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 // indirect
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||||
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41 // indirect
|
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41 // indirect
|
||||||
|
github.com/zitadel/logging v0.6.1 // indirect
|
||||||
|
github.com/zitadel/oidc v1.13.5 // indirect
|
||||||
|
github.com/zitadel/oidc/v3 v3.33.1 // indirect
|
||||||
|
github.com/zitadel/schema v1.3.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.32.0 // indirect
|
go.opentelemetry.io/otel v1.32.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.32.0 // indirect
|
go.opentelemetry.io/otel/metric v1.32.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
||||||
|
@ -56,10 +65,12 @@ require (
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/crypto v0.28.0 // indirect
|
golang.org/x/crypto v0.28.0 // indirect
|
||||||
golang.org/x/net v0.30.0 // indirect
|
golang.org/x/net v0.30.0 // indirect
|
||||||
|
golang.org/x/oauth2 v0.24.0 // indirect
|
||||||
golang.org/x/sync v0.9.0 // indirect
|
golang.org/x/sync v0.9.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
golang.org/x/text v0.19.0 // indirect
|
golang.org/x/text v0.20.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect
|
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect
|
||||||
)
|
)
|
||||||
|
|
29
go.sum
29
go.sum
|
@ -10,6 +10,8 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn
|
||||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
|
github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI=
|
||||||
|
github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
|
||||||
github.com/cskr/pubsub/v2 v2.0.2 h1:395hhPXEsyI1b+5nfj+s5Q3gdxpg0jsWd3t/QAdmU1Y=
|
github.com/cskr/pubsub/v2 v2.0.2 h1:395hhPXEsyI1b+5nfj+s5Q3gdxpg0jsWd3t/QAdmU1Y=
|
||||||
github.com/cskr/pubsub/v2 v2.0.2/go.mod h1:XYuiN8dhcXTCzQDa5SH4+B3zLso94FTwAk0maAEGJJw=
|
github.com/cskr/pubsub/v2 v2.0.2/go.mod h1:XYuiN8dhcXTCzQDa5SH4+B3zLso94FTwAk0maAEGJJw=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -31,6 +33,10 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
@ -48,6 +54,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||||
|
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
@ -97,6 +105,8 @@ github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM=
|
||||||
|
github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
@ -117,6 +127,8 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
|
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
|
||||||
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
|
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
@ -141,6 +153,14 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||||
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41 h1:rnB8ZLMeAr3VcqjfRkAm27qb8y6zFKNfuHvy1Gfe7KI=
|
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41 h1:rnB8ZLMeAr3VcqjfRkAm27qb8y6zFKNfuHvy1Gfe7KI=
|
||||||
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41/go.mod h1:DbzwytT4g/odXquuOCqroKvtxxldI4nb3nuesHF/Exo=
|
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41/go.mod h1:DbzwytT4g/odXquuOCqroKvtxxldI4nb3nuesHF/Exo=
|
||||||
|
github.com/zitadel/logging v0.6.1 h1:Vyzk1rl9Kq9RCevcpX6ujUaTYFX43aa4LkvV1TvUk+Y=
|
||||||
|
github.com/zitadel/logging v0.6.1/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow=
|
||||||
|
github.com/zitadel/oidc v1.13.5 h1:7jhh68NGZitLqwLiVU9Dtwa4IraJPFF1vS+4UupO93U=
|
||||||
|
github.com/zitadel/oidc v1.13.5/go.mod h1:rHs1DhU3Sv3tnI6bQRVlFa3u0lCwtR7S21WHY+yXgPA=
|
||||||
|
github.com/zitadel/oidc/v3 v3.33.1 h1:e3w9PDV0Mh50/ZiJWtzyT0E4uxJ6RXll+hqVDnqGbTU=
|
||||||
|
github.com/zitadel/oidc/v3 v3.33.1/go.mod h1:zkoZ1Oq6CweX3BaLrftLEGCs6YK6zDpjjVGZrP10AWU=
|
||||||
|
github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0=
|
||||||
|
github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc=
|
||||||
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
|
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
|
||||||
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
|
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
|
||||||
|
@ -159,14 +179,21 @@ golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||||
|
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||||
|
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
|
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
|
||||||
|
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
|
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||||
|
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||||
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
|
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
|
||||||
|
@ -176,6 +203,8 @@ google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
120
src/auth/auth.go
Normal file
120
src/auth/auth.go
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/royalcat/konfa-server/pkg/uuid"
|
||||||
|
"github.com/royalcat/konfa-server/src/store"
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/zitadel/oidc/v3/pkg/client/rs"
|
||||||
|
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errMissingMetadata = status.Errorf(codes.InvalidArgument, "missing metadata")
|
||||||
|
errInvalidToken = status.Errorf(codes.Unauthenticated, "invalid token")
|
||||||
|
)
|
||||||
|
|
||||||
|
type AuthenticatorConfig struct {
|
||||||
|
Issuer string
|
||||||
|
ClientID string
|
||||||
|
ClientSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Authenticator struct {
|
||||||
|
provider rs.ResourceServer
|
||||||
|
db *bun.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAuthenticator(ctx context.Context, db *bun.DB, acfg AuthenticatorConfig) (*Authenticator, error) {
|
||||||
|
|
||||||
|
provider, err := rs.NewResourceServerClientCredentials(ctx, acfg.Issuer, acfg.ClientID, acfg.ClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Authenticator{
|
||||||
|
provider: provider,
|
||||||
|
db: db,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Authenticator) authorize(ctx context.Context, token string) (context.Context, error) {
|
||||||
|
// var claims oidc.AccessTokenClaims
|
||||||
|
// _, err := oidc.ParseToken(token, &claims)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
resp, err := rs.Introspect[*oidc.IntrospectionResponse](ctx, a.provider, token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := a.loginWithExternal(ctx, resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, ctxUserKey, &user)
|
||||||
|
|
||||||
|
return ctx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Authenticator) loginWithExternal(ctx context.Context, resp *oidc.IntrospectionResponse) (store.User, error) {
|
||||||
|
var user store.User
|
||||||
|
err := a.db.NewSelect().
|
||||||
|
Model(&user).
|
||||||
|
Join("JOIN external_login ON \"user\".\"id\" = \"external_login\".\"user_id\"").
|
||||||
|
Where("issuer = ?", resp.Issuer).
|
||||||
|
Where("subject = ?", resp.Subject).
|
||||||
|
Scan(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return a.createUserFromExternal(ctx, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return store.User{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Authenticator) createUserFromExternal(ctx context.Context, resp *oidc.IntrospectionResponse) (store.User, error) {
|
||||||
|
user := store.User{
|
||||||
|
ID: uuid.New(),
|
||||||
|
Username: resp.Username,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
|
||||||
|
_, err := tx.NewInsert().
|
||||||
|
Model(&user).
|
||||||
|
Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.NewInsert().
|
||||||
|
Model(&store.ExternalLogin{
|
||||||
|
UserID: user.ID,
|
||||||
|
Issuer: resp.Issuer,
|
||||||
|
Subject: resp.Subject,
|
||||||
|
}).
|
||||||
|
Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return store.User{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
15
src/auth/ctx.go
Normal file
15
src/auth/ctx.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/royalcat/konfa-server/src/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ctxKey string
|
||||||
|
|
||||||
|
const ctxUserKey ctxKey = "user"
|
||||||
|
|
||||||
|
func CtxGetUser(ctx context.Context) *store.User {
|
||||||
|
return ctx.Value(ctxUserKey).(*store.User)
|
||||||
|
}
|
66
src/auth/grpc.go
Normal file
66
src/auth/grpc.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *Authenticator) UnaryAuthenticate(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||||
|
md, ok := metadata.FromIncomingContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
return nil, errMissingMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
token := grpcExtractToken(md["authorization"])
|
||||||
|
if token == "" {
|
||||||
|
return nil, errInvalidToken
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, err := a.authorize(ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Authenticator) StreamAuthenticate(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||||
|
ctx := ss.Context()
|
||||||
|
|
||||||
|
md, ok := metadata.FromIncomingContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
return errMissingMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
token := grpcExtractToken(md["authorization"])
|
||||||
|
if token == "" {
|
||||||
|
return errInvalidToken
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, err := a.authorize(ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler(srv, newWrappedStream(ctx, ss))
|
||||||
|
}
|
||||||
|
|
||||||
|
func grpcExtractToken(authorization []string) string {
|
||||||
|
if len(authorization) < 1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimPrefix(authorization[0], "Bearer ")
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrappedStreamContext struct {
|
||||||
|
ctx context.Context
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWrappedStream(ctx context.Context, s grpc.ServerStream) grpc.ServerStream {
|
||||||
|
return &wrappedStreamContext{ctx: ctx, ServerStream: s}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/royalcat/konfa-server/src/store"
|
"github.com/royalcat/konfa-server/src/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Service) CreateChannel(ctx context.Context, serverID uuid.UUID, name string) (uuid.UUID, error) {
|
func (c *Service) CreateTextChannel(ctx context.Context, serverID uuid.UUID, name string) (uuid.UUID, error) {
|
||||||
channel := store.TextChannel{
|
channel := store.TextChannel{
|
||||||
ID: uuid.New(),
|
ID: uuid.New(),
|
||||||
ServerID: serverID,
|
ServerID: serverID,
|
||||||
|
@ -34,7 +34,7 @@ func (c *Service) GetChannel(ctx context.Context, serverID uuid.UUID, channelID
|
||||||
return channel, err
|
return channel, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Service) ListChannelsOnServer(ctx context.Context, serverID uuid.UUID) ([]store.TextChannel, error) {
|
func (c *Service) ListTextChannelsOnServer(ctx context.Context, serverID uuid.UUID) ([]store.TextChannel, error) {
|
||||||
var channels []store.TextChannel
|
var channels []store.TextChannel
|
||||||
err := c.db.NewSelect().
|
err := c.db.NewSelect().
|
||||||
Model(&channels).
|
Model(&channels).
|
||||||
|
|
|
@ -34,12 +34,3 @@ func (c *Service) ListServers(ctx context.Context) ([]store.Server, error) {
|
||||||
Scan(ctx)
|
Scan(ctx)
|
||||||
return servers, err
|
return servers, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Service) ListTextChannels(ctx context.Context, serverID uuid.UUID) ([]store.TextChannel, error) {
|
|
||||||
var channels []store.TextChannel
|
|
||||||
err := c.db.NewSelect().
|
|
||||||
Model(&channels).
|
|
||||||
Where("server_id = ?", serverID).
|
|
||||||
Scan(ctx)
|
|
||||||
return channels, err
|
|
||||||
}
|
|
||||||
|
|
26
src/konfa/user.go
Normal file
26
src/konfa/user.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package konfa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/royalcat/konfa-server/pkg/uuid"
|
||||||
|
"github.com/royalcat/konfa-server/src/store"
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Users struct {
|
||||||
|
db *bun.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUsers(db *bun.DB) *Users {
|
||||||
|
return &Users{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Users) GetUser(ctx context.Context, id uuid.UUID) (store.User, error) {
|
||||||
|
var user store.User
|
||||||
|
err := u.db.NewSelect().
|
||||||
|
Model(&user).
|
||||||
|
Where("id = ?", id).
|
||||||
|
Scan(ctx)
|
||||||
|
return user, err
|
||||||
|
}
|
|
@ -1,97 +0,0 @@
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"flag"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/royalcat/konfa-server/pkg/uuid"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errMissingMetadata = status.Errorf(codes.InvalidArgument, "missing metadata")
|
|
||||||
errInvalidToken = status.Errorf(codes.Unauthenticated, "invalid token")
|
|
||||||
)
|
|
||||||
|
|
||||||
var port = flag.Int("port", 50051, "the port to serve on")
|
|
||||||
|
|
||||||
// func main() {
|
|
||||||
// flag.Parse()
|
|
||||||
// fmt.Printf("server starting on port %d...\n", *port)
|
|
||||||
|
|
||||||
// cert, err := tls.LoadX509KeyPair(data.Path("x509/server_cert.pem"), data.Path("x509/server_key.pem"))
|
|
||||||
// if err != nil {
|
|
||||||
// log.Fatalf("failed to load key pair: %s", err)
|
|
||||||
// }
|
|
||||||
// opts := []grpc.ServerOption{
|
|
||||||
// // The following grpc.ServerOption adds an interceptor for all unary
|
|
||||||
// // RPCs. To configure an interceptor for streaming RPCs, see:
|
|
||||||
// // https://godoc.org/google.golang.org/grpc#StreamInterceptor
|
|
||||||
// grpc.UnaryInterceptor(ensureValidToken),
|
|
||||||
// // Enable TLS for all incoming connections.
|
|
||||||
// grpc.Creds(credentials.NewServerTLSFromCert(&cert)),
|
|
||||||
// }
|
|
||||||
// s := grpc.NewServer(opts...)
|
|
||||||
// pb.RegisterEchoServer(s, &ecServer{})
|
|
||||||
// lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
|
|
||||||
// if err != nil {
|
|
||||||
// log.Fatalf("failed to listen: %v", err)
|
|
||||||
// }
|
|
||||||
// if err := s.Serve(lis); err != nil {
|
|
||||||
// log.Fatalf("failed to serve: %v", err)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// valid validates the authorization.
|
|
||||||
func valid(authorization []string) bool {
|
|
||||||
if len(authorization) < 1 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
token := strings.TrimPrefix(authorization[0], "Bearer ")
|
|
||||||
// Perform the token validation here. For the sake of this example, the code
|
|
||||||
// here forgoes any of the usual OAuth2 token validation and instead checks
|
|
||||||
// for a token matching an arbitrary string.
|
|
||||||
return token == "some-secret-token"
|
|
||||||
}
|
|
||||||
|
|
||||||
type ctxKey string
|
|
||||||
|
|
||||||
const ctxUserKey ctxKey = "user"
|
|
||||||
|
|
||||||
// Authenticate ensures a valid token exists within a request's metadata. If
|
|
||||||
// the token is missing or invalid, the interceptor blocks execution of the
|
|
||||||
// handler and returns an error. Otherwise, the interceptor invokes the unary
|
|
||||||
// handler.
|
|
||||||
func Authenticate(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
|
||||||
// md, ok := metadata.FromIncomingContext(ctx)
|
|
||||||
// if !ok {
|
|
||||||
// return nil, errMissingMetadata
|
|
||||||
// }
|
|
||||||
// // The keys within metadata.MD are normalized to lowercase.
|
|
||||||
// // See: https://godoc.org/google.golang.org/grpc/metadata#New
|
|
||||||
// if !valid(md["authorization"]) {
|
|
||||||
// return nil, errInvalidToken
|
|
||||||
// }
|
|
||||||
|
|
||||||
var user User
|
|
||||||
|
|
||||||
user = User{
|
|
||||||
ID: uuid.MustFromString("a903b474-26f4-4262-9ba7-97edaa76491f"),
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, ctxUserKey, &user)
|
|
||||||
|
|
||||||
// Continue execution of handler after ensuring a valid token.
|
|
||||||
return handler(ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
ID uuid.UUID
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCtxUser(ctx context.Context) *User {
|
|
||||||
return ctx.Value(ctxUserKey).(*User)
|
|
||||||
}
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/royalcat/konfa-server/pkg/uuid"
|
"github.com/royalcat/konfa-server/pkg/uuid"
|
||||||
|
"github.com/royalcat/konfa-server/src/auth"
|
||||||
"github.com/royalcat/konfa-server/src/konfa"
|
"github.com/royalcat/konfa-server/src/konfa"
|
||||||
chatv1 "github.com/royalcat/konfa-server/src/proto/konfa/chat/v1"
|
chatv1 "github.com/royalcat/konfa-server/src/proto/konfa/chat/v1"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
@ -27,7 +28,7 @@ var _ chatv1.ChatServiceServer = (*ChatService)(nil)
|
||||||
|
|
||||||
// SendMessage implements chatv1.ChatServiceServer.
|
// SendMessage implements chatv1.ChatServiceServer.
|
||||||
func (c *ChatService) SendMessage(ctx context.Context, req *chatv1.SendMessageRequest) (*chatv1.SendMessageResponse, error) {
|
func (c *ChatService) SendMessage(ctx context.Context, req *chatv1.SendMessageRequest) (*chatv1.SendMessageResponse, error) {
|
||||||
user := getCtxUser(ctx)
|
user := auth.CtxGetUser(ctx)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return nil, ErrUnauthenticated
|
return nil, ErrUnauthenticated
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ func (s *ServerService) ListServerChannels(ctx context.Context, req *serverv1.Li
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
textChannels, err := s.srv.ListTextChannels(ctx, serverID)
|
textChannels, err := s.srv.ListTextChannelsOnServer(ctx, serverID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
25
src/store/models_user.go
Normal file
25
src/store/models_user.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/royalcat/konfa-server/pkg/uuid"
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
bun.BaseModel `bun:"table:user"`
|
||||||
|
|
||||||
|
ID uuid.UUID `bun:"id,pk"`
|
||||||
|
Username string `bun:"username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExternalLogin struct {
|
||||||
|
bun.BaseModel `bun:"table:external_login"`
|
||||||
|
|
||||||
|
ID uuid.UUID `bun:"id,pk"`
|
||||||
|
UserID uuid.UUID `bun:"user_id"`
|
||||||
|
Issuer string `bun:"issuer"`
|
||||||
|
Subject string `bun:"subject"`
|
||||||
|
CreatedAt time.Time `bun:"created_at"`
|
||||||
|
}
|
|
@ -3,32 +3,28 @@
|
||||||
-- User Table
|
-- User Table
|
||||||
CREATE TABLE "user" (
|
CREATE TABLE "user" (
|
||||||
id uuid PRIMARY KEY,
|
id uuid PRIMARY KEY,
|
||||||
username VARCHAR(255) UNIQUE
|
username VARCHAR(255) NOT NULL UNIQUE
|
||||||
);
|
);
|
||||||
-- Server Table
|
-- Server Table
|
||||||
CREATE TABLE "server" (id uuid PRIMARY KEY, "name" VARCHAR(255));
|
CREATE TABLE "server" (id uuid PRIMARY KEY, "name" VARCHAR(255));
|
||||||
-- TextChannel Table
|
-- TextChannel Table
|
||||||
CREATE TABLE "text_channel" (
|
CREATE TABLE "text_channel" (
|
||||||
id uuid PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
server_id uuid,
|
server_id UUID NOT NULL REFERENCES "server"(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (server_id) REFERENCES "server"(id),
|
"name" VARCHAR(255) NOT NULL
|
||||||
"name" VARCHAR(255)
|
|
||||||
);
|
);
|
||||||
CREATE UNIQUE INDEX unique_text_channel_name ON "text_channel"(server_id, "name");
|
CREATE UNIQUE INDEX unique_text_channel_name ON "text_channel"(server_id, "name");
|
||||||
-- VoiceChannel Table
|
-- VoiceChannel Table
|
||||||
CREATE TABLE "voice_channel" (
|
CREATE TABLE "voice_channel" (
|
||||||
id uuid PRIMARY KEY,
|
id uuid PRIMARY KEY,
|
||||||
server_id uuid,
|
server_id uuid NOT NULL REFERENCES "server"(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (server_id) REFERENCES "server"(id),
|
"name" VARCHAR(255) NOT NULL
|
||||||
"name" VARCHAR(255)
|
|
||||||
);
|
);
|
||||||
-- Message Table
|
-- Message Table
|
||||||
CREATE TABLE "message" (
|
CREATE TABLE "message" (
|
||||||
id uuid PRIMARY KEY,
|
id uuid PRIMARY KEY,
|
||||||
channel_id uuid NOT NULL,
|
channel_id uuid NOT NULL REFERENCES "text_channel"(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (channel_id) REFERENCES "text_channel"(id),
|
sender_id uuid NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
|
||||||
sender_id uuid NOT NULL,
|
|
||||||
FOREIGN KEY (sender_id) REFERENCES "user"(id),
|
|
||||||
content TEXT NOT NULL,
|
content TEXT NOT NULL,
|
||||||
"timestamp" TIMESTAMPTZ NOT NULL DEFAULT now()
|
"timestamp" TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
);
|
);
|
||||||
|
|
11
src/store/pg_migrations/2_external_logins.sql
Normal file
11
src/store/pg_migrations/2_external_logins.sql
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
CREATE TABLE "external_login" (
|
||||||
|
"id" uuid PRIMARY KEY,
|
||||||
|
"user_id" uuid NOT NULL REFERENCES "user" (id) ON DELETE CASCADE,
|
||||||
|
"issuer" TEXT NOT NULL,
|
||||||
|
"subject" TEXT NOT NULL,
|
||||||
|
"created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE UNIQUE INDEX external_login_unique_external_id ON "external_login" ("issuer", "subject");
|
||||||
|
-- +goose StatementEnd
|
Loading…
Reference in a new issue