Skip to content

Commit 9a89acb

Browse files
committed
[jwt] add module and config
1 parent 1759faf commit 9a89acb

File tree

13 files changed

+319
-0
lines changed

13 files changed

+319
-0
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ require (
1515
github.com/go-sql-driver/mysql v1.7.1
1616
github.com/gofiber/fiber/v2 v2.52.9
1717
github.com/gofiber/swagger v1.1.1
18+
github.com/golang-jwt/jwt/v5 v5.3.0
1819
github.com/google/uuid v1.6.0
1920
github.com/jaevor/go-nanoid v1.3.0
2021
github.com/nyaruka/phonenumbers v1.4.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
128128
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
129129
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
130130
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
131+
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
132+
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
131133
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
132134
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
133135
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=

internal/config/config.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package config
22

3+
import "time"
4+
35
type GatewayMode string
46

57
const (
@@ -17,6 +19,7 @@ type Config struct {
1719
Messages Messages `yaml:"messages"` // messages config
1820
Cache Cache `yaml:"cache"` // cache (memory or redis) config
1921
PubSub PubSub `yaml:"pubsub"` // pubsub (memory or redis) config
22+
JWT JWT `yaml:"jwt"` // jwt config
2023
}
2124

2225
type Gateway struct {
@@ -85,6 +88,12 @@ type PubSub struct {
8588
URL string `yaml:"url" envconfig:"PUBSUB__URL"`
8689
}
8790

91+
type JWT struct {
92+
Secret string `yaml:"secret" envconfig:"JWT__SECRET"`
93+
TTL Duration `yaml:"ttl" envconfig:"JWT__TTL"`
94+
Issuer string `yaml:"issuer" envconfig:"JWT__ISSUER"`
95+
}
96+
8897
var defaultConfig = Config{
8998
Gateway: Gateway{Mode: GatewayModePublic},
9099
HTTP: HTTP{
@@ -119,4 +128,8 @@ var defaultConfig = Config{
119128
PubSub: PubSub{
120129
URL: "memory://",
121130
},
131+
JWT: JWT{
132+
TTL: Duration(time.Hour * 24),
133+
Issuer: "sms-gate.app",
134+
},
122135
}

internal/config/module.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/android-sms-gateway/server/internal/sms-gateway/cache"
88
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers"
9+
"github.com/android-sms-gateway/server/internal/sms-gateway/jwt"
910
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/auth"
1011
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/devices"
1112
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/messages"
@@ -124,4 +125,11 @@ var Module = fx.Module(
124125
BufferSize: 128,
125126
}
126127
}),
128+
fx.Provide(func(cfg Config) jwt.Config {
129+
return jwt.Config{
130+
Secret: cfg.JWT.Secret,
131+
TTL: time.Duration(cfg.JWT.TTL),
132+
Issuer: cfg.JWT.Issuer,
133+
}
134+
}),
127135
)

internal/config/types.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package config
2+
3+
import (
4+
"encoding"
5+
"fmt"
6+
"time"
7+
8+
"gopkg.in/yaml.v3"
9+
)
10+
11+
type Duration time.Duration
12+
13+
// Duration returns the underlying time.Duration value.
14+
func (d *Duration) Duration() time.Duration {
15+
if d == nil {
16+
return 0
17+
}
18+
return time.Duration(*d)
19+
}
20+
21+
// String returns the string representation of the duration.
22+
func (d *Duration) String() string {
23+
if d == nil {
24+
return ""
25+
}
26+
return time.Duration(*d).String()
27+
}
28+
29+
func (d *Duration) UnmarshalText(text []byte) error {
30+
t, err := time.ParseDuration(string(text))
31+
if err != nil {
32+
return fmt.Errorf("can't parse duration: %w", err)
33+
}
34+
*d = Duration(t)
35+
return nil
36+
}
37+
38+
func (d *Duration) UnmarshalYAML(value *yaml.Node) error {
39+
var s string
40+
if err := value.Decode(&s); err != nil {
41+
return fmt.Errorf("can't unmarshal duration: %w", err)
42+
}
43+
44+
return d.UnmarshalText([]byte(s))
45+
}
46+
47+
var _ yaml.Unmarshaler = (*Duration)(nil)
48+
var _ encoding.TextUnmarshaler = (*Duration)(nil)

internal/sms-gateway/app.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
appconfig "github.com/android-sms-gateway/server/internal/config"
88
"github.com/android-sms-gateway/server/internal/sms-gateway/cache"
99
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers"
10+
"github.com/android-sms-gateway/server/internal/sms-gateway/jwt"
1011
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/auth"
1112
appdb "github.com/android-sms-gateway/server/internal/sms-gateway/modules/db"
1213
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/devices"
@@ -53,6 +54,7 @@ var Module = fx.Module(
5354
metrics.Module,
5455
sse.Module,
5556
online.Module(),
57+
jwt.Module(),
5658
)
5759

5860
func Run() {

internal/sms-gateway/jwt/config.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package jwt
2+
3+
import (
4+
"fmt"
5+
"time"
6+
)
7+
8+
type Config struct {
9+
Secret string
10+
TTL time.Duration
11+
Issuer string
12+
}
13+
14+
func (c Config) Validate() error {
15+
if c.Secret == "" {
16+
return fmt.Errorf("%w: secret is required", ErrInvalidConfig)
17+
}
18+
19+
if c.TTL == 0 {
20+
return fmt.Errorf("%w: ttl must be positive", ErrInvalidConfig)
21+
}
22+
23+
return nil
24+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package jwt
2+
3+
import (
4+
"context"
5+
"time"
6+
)
7+
8+
type disabled struct {
9+
}
10+
11+
func newDisabled() Service {
12+
return &disabled{}
13+
}
14+
15+
// GenerateToken implements Service.
16+
func (d *disabled) GenerateToken(userID string, scopes []string, ttl time.Duration) (string, error) {
17+
return "", ErrDisabled
18+
}
19+
20+
// ParseToken implements Service.
21+
func (d *disabled) ParseToken(ctx context.Context, token string) (*Claims, error) {
22+
return nil, ErrDisabled
23+
}
24+
25+
// RevokeToken implements Service.
26+
func (d *disabled) RevokeToken(ctx context.Context, jti string) error {
27+
return ErrDisabled
28+
}

internal/sms-gateway/jwt/errors.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package jwt
2+
3+
import "errors"
4+
5+
var (
6+
ErrDisabled = errors.New("jwt disabled")
7+
ErrInitFailed = errors.New("failed to initialize jwt")
8+
ErrInvalidConfig = errors.New("invalid config")
9+
ErrTokenRevoked = errors.New("token revoked")
10+
ErrUnexpectedSigningMethod = errors.New("unexpected signing method")
11+
)

internal/sms-gateway/jwt/jwt.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package jwt
2+
3+
import "github.com/golang-jwt/jwt/v5"
4+
5+
type Claims struct {
6+
jwt.RegisteredClaims
7+
8+
UserID string `json:"user_id"`
9+
Scopes []string `json:"scopes"`
10+
}

0 commit comments

Comments
 (0)