-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
289 lines (269 loc) · 7.86 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
/**
* @Author: Li Feiyang
* @Date: 2022/11/9 10:57
*/
package main
import (
"context"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
"log"
"net/http"
"strconv"
"time"
)
const Database = "pastebin"
//var languageList = []string{"C", "C++", "Java", "Python", "Go", "JavaScript"}
/**
* 连接数据库。
* 值得注意的是调用了 DataInit(client) 和 VerifyInit(client),这是MongoDB TTL功能的要求:开启计时器以支持自动删除功能。
* @return : *mongo.Client
*/
func con() *mongo.Client {
serverAPIOptions := options.ServerAPI(options.ServerAPIVersion1)
clientOptions := options.Client().
ApplyURI("mongodb+srv://xfydemx:[email protected]/?retryWrites=true&w=majority").
SetServerAPIOptions(serverAPIOptions)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
log.Fatal(err)
}
if err := client.Ping(context.TODO(), readpref.Primary()); err != nil {
logrus.Fatal("FAILED to connect MongoDB!")
} else {
logrus.Info("Successfully connected MongoDB and pinged.")
}
DataInit(client)
VerifyInit(client)
return client
}
/**
* 为服务提供各种路由方法。
*/
func setupRouter(client *mongo.Client) *gin.Engine {
r := gin.Default()
r.GET("/pastebin/verify", func(c *gin.Context) {
//param := c.Request.URL.RawQuery
})
/**
* POST方法,接收包含密码的表单。查数据库进行比对,如果通过就设置一条cookie,
* 向数据库中添加临时条目(过期时间为 30 分钟),内容为用户的 sessionId 和该 sessionId 已被授权访问的网页地址。
*/
r.POST("/pastebin/verify", func(c *gin.Context) {
password := c.PostForm("password")
paramUrl := c.PostForm("url")
/*param := c.Request.URL.RawQuery
result := strings.Split(param, "=")
paramUrl := result[len(result)-1]*/
logrus.Info("Verify url + " + paramUrl + " with password: " + password)
if passwordVerify(client, password, paramUrl) == true {
// 密码正确
sessionID, err := c.Cookie("sessionID")
if err != nil {
sessionID = generateUrl()
logrus.Info("Rand sessionID generated:" + sessionID)
c.SetCookie("sessionID", sessionID, 1800, "/", "localhost", false, true)
}
//c.String(http.StatusOK, "VERIFY SUCCESS!")
InsertVerify(client, sessionID, paramUrl)
logrus.Info("Verify succeeded, redirect to: " + paramUrl)
c.Redirect(http.StatusFound, "/pastebin/"+paramUrl)
} else {
//密码错误
//c.String(http.StatusOK, "VERIFY FAIL!")
c.JSON(http.StatusOK, gin.H{
"message": "POST",
"code": 0,
"data": gin.H{
"status": 10003,
},
})
}
})
/**
* POST方法,接收包含文件数据的表单。
* 初始化文件数据结构File,然后对数据进行校验,若通过则加入数据库
*
*/
r.POST("/pastebin/file", func(c *gin.Context) {
logrus.Info("POST: submit file data")
var fileStruct = new(File)
// 允许访问的次数(默认1
times := c.DefaultPostForm("times", "1")
fileStruct.Times, _ = strconv.Atoi(times)
// 到期自动删除的时间(默认3600s = 60min
expire := c.DefaultPostForm("expire", "3600")
intExpire, _ := strconv.Atoi(expire)
// 设置MongoDB的TTL
fileStruct.Timestamp = time.Now()
fileStruct.CreatedAt = time.Now().Add(time.Second * time.Duration(intExpire))
// 密码和Url
fileStruct.Password = c.PostForm("password")
fileStruct.Url = generateUrl()
logrus.Info("Rnd url generated:" + fileStruct.Url)
var result bool
//var err error
// 获取上传的文件头
file, fileHeader, err := c.Request.FormFile("data")
if err != nil {
logrus.Error("Submit file: unknown error!" + err.Error())
c.JSON(http.StatusOK, gin.H{
"message": "POST",
"code": 0,
"data": gin.H{
"status": 10003,
},
})
} else {
fileStruct.Name = fileHeader.Filename
//处理文件数据并校验
fileStruct.Data, result, fileStruct.Category = getFileData(c, file, fileHeader)
if result == true { // 通过校验
err2 := installFile(client, *fileStruct)
if err2 != nil {
c.JSON(http.StatusOK, gin.H{
"message": "POST",
"code": 0,
"data": gin.H{
"status": 10003,
},
})
} else { //不通过校验
c.JSON(http.StatusOK, gin.H{
"message": "POST",
"code": 0,
"data": gin.H{
"status": 0,
"url": fileStruct.Url,
},
})
}
}
}
})
/**
* POST方法,接收包含上传的代码的表单。
*
*/
r.POST("/pastebin/submit", func(c *gin.Context) {
logrus.Info("POST: submit text")
var file = new(File)
// 下载次数(默认1
times := c.DefaultPostForm("times", "1")
file.Times, _ = strconv.Atoi(times)
// 过期时间(默认3600s = 60min
expire := c.DefaultPostForm("expire", "3600")
intExpire, _ := strconv.Atoi(expire)
// 密码
file.Password = c.PostForm("password")
file.Url = generateUrl()
logrus.Info("Url generated : " + file.Url)
// MongoDB TTL 时间戳
file.Timestamp = time.Now()
file.CreatedAt = time.Now().Add(time.Second * time.Duration(intExpire))
if c.PostForm("highlight") == "true" {
file.Highlight = true
} else {
file.Highlight = false
}
file.Text = c.PostForm("text")
file.Language = c.PostForm("language")
//上传加入数据库并处理错误
err := installFile(client, *file)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"message": "POST",
"code": 0,
"data": gin.H{
"status": 10001,
"url": "",
},
})
} else {
c.JSON(http.StatusOK, gin.H{
"message": "POST",
"code": 0,
"data": gin.H{
"status": 0,
"url": file.Url,
},
})
}
})
/**
* 试图访问获取资源。首先检查是否有有效的 SessionID,若没有则直接跳转到验证页面,
* 否则检查数据库是否能查询到数据,视情况返回数据。
*/
r.GET("/pastebin/:path", func(c *gin.Context) {
//c.Header("Content-Type", "text/markdown")
path := c.Param("path")
logrus.Info("GET: get the data of url: " + path)
sessionID, _ := c.Cookie("sessionID")
// 检查有无有效的sessionID
err, result := verifySessionID(client, sessionID, path)
if err != nil {
c.JSON(http.StatusOK, gin.H{ // TODO: API update
"message": "GET",
"code": 0,
"data": gin.H{
"status": 10001, // Session 验证出现问题
},
})
} else if result == true {
// 如果有 SessionID, 向前端查询数据,视情况是否返回文件
path := c.Param("path")
e, result, FILE := queryUrl(client, path)
if e != nil {
c.JSON(http.StatusOK, gin.H{ // TODO: API update
"message": "GET",
"code": 0,
"data": gin.H{
"status": 10001, // 查询数据过程出现问题
},
})
} else if result && FILE.Times > 0 {
switch FILE.Category {
case "txt":
c.Header("Content-Type", "text/plain")
case "md":
c.Header("Content-Type", "text/markdown")
case "csv":
c.Header("Content-Type", "text/csv")
case "tex":
c.Header("Content-Type", "text/x-tex")
default:
c.Header("Content-Type", "text/plain")
}
returnData(client, c)
} else {
// result == false
c.JSON(http.StatusOK, gin.H{ // TODO: API update
"message": "GET",
"code": 0,
"data": gin.H{
"status": 10001, // 获取不到文件(数据库找不到文件)
},
})
}
} else {
// 没有session 则跳转到验证
logrus.Info("Redirect to verify Page!")
c.Redirect(http.StatusMovedPermanently, "/pastebin/verify?url="+path)
}
})
return r
}
func main() {
logrus.SetLevel(logrus.TraceLevel)
client := con()
r := setupRouter(client)
err := r.Run(":8080")
if err != nil {
logrus.Fatal("ERROR in Run client in port 8080!")
}
}