Skip to content

Commit 4bff562

Browse files
authored
Merge branch 'main' into syncCustom
Signed-off-by: Pentyd <69415577+Penty-d@users.noreply.github.com>
2 parents 3da9e1d + a2eb592 commit 4bff562

19 files changed

Lines changed: 789 additions & 193 deletions

api/mw/token.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,13 @@ limitations under the License.
1717
package mw
1818

1919
import (
20+
"crypto"
21+
"crypto/ed25519"
22+
"crypto/x509"
23+
"encoding/pem"
2024
"errors"
2125
"fmt"
26+
"sync"
2227
"time"
2328

2429
"github.com/golang-jwt/jwt/v4"
@@ -108,17 +113,17 @@ func CheckToken(token string) (int64, string, error) {
108113
return -1, "", errno.AuthError.WithMessage("cannot handle claims")
109114
}
110115

111-
secret, err := jwt.ParseEdPublicKeyFromPEM([]byte(constants.PublicKey))
116+
publicKey, err := getPublicKey()
112117
if err != nil {
113-
return -1, "", errno.AuthError.WithMessage(fmt.Sprintf("parse public key failed, err: %v", err))
118+
return -1, "", errno.AuthError.WithMessage(fmt.Sprintf("get public key failed, err: %v", err))
114119
}
115120

116121
// 使用正确的密钥再次解析 token
117122
response, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
118123
if _, ok := token.Method.(*jwt.SigningMethodEd25519); !ok {
119124
return nil, errno.AuthError.WithMessage(fmt.Sprintf("unexpected signing method: %v", token.Header["alg"]))
120125
}
121-
return secret, nil
126+
return publicKey, nil
122127
})
123128
// 验证 token 是否有效
124129
if err != nil {
@@ -145,3 +150,22 @@ func checkError(err error, tokenType int64) error {
145150
}
146151
return errno.AuthError.WithMessage(err.Error())
147152
}
153+
154+
var getPublicKey = sync.OnceValues(func() (crypto.PublicKey, error) {
155+
block, _ := pem.Decode([]byte(config.Server.Secret))
156+
if block == nil {
157+
return nil, fmt.Errorf("failed to decode PEM block")
158+
}
159+
160+
keyAny, err := x509.ParsePKCS8PrivateKey(block.Bytes)
161+
if err != nil {
162+
return nil, fmt.Errorf("failed to parse PKCS8 private key: %w", err)
163+
}
164+
165+
privateKey, ok := keyAny.(ed25519.PrivateKey)
166+
if !ok {
167+
return nil, fmt.Errorf("key is not ed25519 private key")
168+
}
169+
170+
return privateKey.Public(), nil
171+
})

config/config.go

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ limitations under the License.
1717
package config
1818

1919
import (
20-
"errors"
21-
"log"
20+
"bytes"
21+
"context"
2222
"os"
2323
"path/filepath"
24+
"time"
2425

2526
"github.com/fsnotify/fsnotify"
2627
"github.com/spf13/viper"
27-
_ "github.com/spf13/viper/remote"
28+
clientv3 "go.etcd.io/etcd/client/v3"
2829

2930
"github.com/west2-online/fzuhelper-server/pkg/constants"
3031
"github.com/west2-online/fzuhelper-server/pkg/logger"
@@ -56,10 +57,13 @@ var (
5657
)
5758

5859
const (
59-
remoteProvider = "etcd3" // 使用 etcd3
60-
remotePath = "/config"
61-
remoteFileName = "config"
62-
remoteFileType = "yaml"
60+
// remotePath 是配置在 etcd 中的存储 key,value 为 yaml 内容。
61+
// 原实现通过 viper/remote + sagikazarmark/crypt 读取,但该依赖链会引入
62+
// golang.org/x/crypto/openpgp(GO-2026-5932,该包无人维护、无修复版本),
63+
// 因此改为直接使用 etcd client/v3 读取,行为保持一致。
64+
remotePath = "/config"
65+
remoteFileType = "yaml"
66+
etcdReadTimeout = 3 * time.Second
6367
)
6468

6569
func Init(service string) {
@@ -82,17 +86,30 @@ func InitFromETCD(service string) {
8286
Etcd = &etcd{Addr: etcdAddr}
8387

8488
// 配置存储在 etcd 中
85-
err := runtimeViper.AddRemoteProvider(remoteProvider, Etcd.Addr, remotePath)
89+
cli, err := clientv3.New(clientv3.Config{
90+
Endpoints: []string{etcdAddr},
91+
})
8692
if err != nil {
87-
logger.Fatalf("config.Init: add remote provider error: %v", err)
93+
logger.Fatalf("config.Init: create etcd client error: %v", err)
8894
}
89-
runtimeViper.SetConfigName(remoteFileName)
90-
runtimeViper.SetConfigType(remoteFileType)
91-
if err := runtimeViper.ReadRemoteConfig(); err != nil {
92-
var configFileNotFoundError viper.ConfigFileNotFoundError
93-
if errors.As(err, &configFileNotFoundError) {
94-
log.Fatal("config.Init: could not find config files")
95+
defer func() {
96+
if err := cli.Close(); err != nil {
97+
logger.Errorf("config.Init: close etcd client error: %v", err)
9598
}
99+
}()
100+
101+
ctx, cancel := context.WithTimeout(context.Background(), etcdReadTimeout)
102+
defer cancel()
103+
resp, err := cli.Get(ctx, remotePath)
104+
if err != nil {
105+
logger.Fatalf("config.Init: read config from etcd error: %v", err)
106+
}
107+
if len(resp.Kvs) != 1 {
108+
logger.Fatalf("config.Init: config not found in etcd, key: %s", remotePath)
109+
}
110+
111+
runtimeViper.SetConfigType(remoteFileType)
112+
if err := runtimeViper.ReadConfig(bytes.NewReader(resp.Kvs[0].Value)); err != nil {
96113
logger.Fatalf("config.Init: read config error: %v", err)
97114
}
98115
configMapping(service)

config/sql/init.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ CREATE TABLE `fzu-helper`.`course_offerings` (
5151
UNIQUE INDEX `uniq_course_hash` (`course_hash`)
5252
) ENGINE=InnoDB CHARSET=utf8mb4;
5353

54+
CREATE TABLE `fzu-helper`.`exam_offerings` (
55+
`id` BIGINT NOT NULL AUTO_INCREMENT,
56+
`exam_hash` CHAR(64) NOT NULL COMMENT '通过课程和新旧考试信息生成的唯一hash',
57+
`tag` VARCHAR(32) NOT NULL COMMENT '考试/考场通知使用的友盟tag',
58+
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
59+
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
60+
`deleted_at` TIMESTAMP NULL DEFAULT NULL,
61+
PRIMARY KEY (`id`),
62+
UNIQUE INDEX `uniq_exam_hash` (`exam_hash`)
63+
) ENGINE=InnoDB CHARSET=utf8mb4;
64+
5465
create table `fzu-helper`.`launch_screen`(
5566
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
5667
`url` tinytext NULL COMMENT '图片url',
@@ -80,6 +91,8 @@ CREATE TABLE `fzu-helper`.`course`(
8091
`term` varchar(16) NOT NULL COMMENT '学期',
8192
`term_courses` json NOT NULL COMMENT '学期课程信息',
8293
`term_courses_sha256` varchar(64) NOT NULL COMMENT '学期课程信息SHA256',
94+
`exam_info` json NULL COMMENT '我的选课页面考试信息',
95+
`exam_info_sha256` varchar(64) NULL COMMENT '考试信息SHA256',
8396
`created_at` timestamp NOT NULL DEFAULT current_timestamp,
8497
`updated_at` timestamp NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp,
8598
`deleted_at` timestamp NULL DEFAULT NULL,

go.mod

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ require (
2929
github.com/sashabaranov/go-openai v1.41.2
3030
github.com/segmentio/kafka-go v0.4.50
3131
github.com/spf13/viper v1.21.0
32-
github.com/spf13/viper/remote v1.20.1
3332
github.com/upyun/go-sdk/v3 v3.0.4
3433
github.com/west2-online/jwch v0.2.44
3534
github.com/west2-online/yjsy v0.0.10
@@ -77,16 +76,9 @@ require (
7776
)
7877

7978
require (
80-
cloud.google.com/go v0.123.0 // indirect
81-
cloud.google.com/go/auth v0.18.2 // indirect
82-
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
83-
cloud.google.com/go/compute/metadata v0.9.0 // indirect
84-
cloud.google.com/go/firestore v1.21.0 // indirect
85-
cloud.google.com/go/longrunning v0.8.0 // indirect
8679
filippo.io/edwards25519 v1.2.0 // indirect
8780
github.com/antchfx/htmlquery v1.3.6 // indirect
8881
github.com/antchfx/xpath v1.3.6 // indirect
89-
github.com/armon/go-metrics v0.4.1 // indirect
9082
github.com/beorn7/perks v1.0.1 // indirect
9183
github.com/bytedance/sonic/loader v0.5.0 // indirect
9284
github.com/cespare/xxhash/v2 v2.3.0 // indirect
@@ -102,9 +94,7 @@ require (
10294
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
10395
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
10496
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
105-
github.com/fatih/color v1.18.0 // indirect
10697
github.com/fatih/structtag v1.2.0 // indirect
107-
github.com/felixge/httpsnoop v1.0.4 // indirect
10898
github.com/go-logr/logr v1.4.3 // indirect
10999
github.com/go-logr/stdr v1.2.2 // indirect
110100
github.com/go-ole/go-ole v1.3.0 // indirect
@@ -121,16 +111,6 @@ require (
121111
github.com/googleapis/gax-go/v2 v2.17.0 // indirect
122112
github.com/gopherjs/gopherjs v1.17.2 // indirect
123113
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
124-
github.com/hashicorp/consul/api v1.33.4 // indirect
125-
github.com/hashicorp/errwrap v1.1.0 // indirect
126-
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
127-
github.com/hashicorp/go-hclog v1.6.3 // indirect
128-
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
129-
github.com/hashicorp/go-metrics v0.5.4 // indirect
130-
github.com/hashicorp/go-multierror v1.1.1 // indirect
131-
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
132-
github.com/hashicorp/golang-lru v1.0.2 // indirect
133-
github.com/hashicorp/serf v0.10.2 // indirect
134114
github.com/iancoleman/strcase v0.3.0 // indirect
135115
github.com/jhump/protoreflect v1.18.0 // indirect
136116
github.com/jhump/protoreflect/v2 v2.0.0-beta.2 // indirect
@@ -141,15 +121,9 @@ require (
141121
github.com/klauspost/compress v1.18.4 // indirect
142122
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
143123
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect
144-
github.com/mattn/go-colorable v0.1.14 // indirect
145-
github.com/mattn/go-isatty v0.0.20 // indirect
146-
github.com/mitchellh/go-homedir v1.1.0 // indirect
147124
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
148125
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
149126
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
150-
github.com/nats-io/nats.go v1.49.0 // indirect
151-
github.com/nats-io/nkeys v0.4.15 // indirect
152-
github.com/nats-io/nuid v1.0.1 // indirect
153127
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
154128
github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect
155129
github.com/pierrec/lz4/v4 v4.1.26 // indirect
@@ -160,7 +134,6 @@ require (
160134
github.com/prometheus/client_model v0.6.2 // indirect
161135
github.com/prometheus/common v0.67.5 // indirect
162136
github.com/prometheus/procfs v0.20.1 // indirect
163-
github.com/sagikazarmark/crypt v0.31.0 // indirect
164137
github.com/sagikazarmark/locafero v0.12.0 // indirect
165138
github.com/shirou/gopsutil/v3 v3.24.5 // indirect
166139
github.com/shoenig/go-m1cpu v0.1.7 // indirect
@@ -181,11 +154,9 @@ require (
181154
github.com/yusufpapurcu/wmi v1.2.4 // indirect
182155
go.etcd.io/etcd/api/v3 v3.6.8 // indirect
183156
go.etcd.io/etcd/client/pkg/v3 v3.6.8 // indirect
184-
go.etcd.io/etcd/client/v2 v2.305.27 // indirect
185-
go.etcd.io/etcd/client/v3 v3.6.8 // indirect
157+
go.etcd.io/etcd/client/v3 v3.6.8
186158
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
187159
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 // indirect
188-
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect
189160
go.opentelemetry.io/otel v1.44.0
190161
go.opentelemetry.io/otel/metric v1.44.0 // indirect
191162
go.opentelemetry.io/otel/trace v1.44.0
@@ -195,14 +166,10 @@ require (
195166
go.yaml.in/yaml/v3 v3.0.4 // indirect
196167
golang.org/x/arch v0.24.0 // indirect
197168
golang.org/x/crypto v0.52.0 // indirect
198-
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
199169
golang.org/x/net v0.55.0 // indirect
200-
golang.org/x/oauth2 v0.36.0 // indirect
201170
golang.org/x/sys v0.45.0 // indirect
202171
golang.org/x/text v0.39.0 // indirect
203172
golang.org/x/time v0.15.0 // indirect
204-
google.golang.org/api v0.270.0 // indirect
205-
google.golang.org/genproto v0.0.0-20260226221140-a57be14db171 // indirect
206173
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect
207174
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect
208175
google.golang.org/grpc v1.82.1 // indirect

0 commit comments

Comments
 (0)