diff --git a/config.example.yaml b/config.example.yaml index fcb9709..5dff392 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -15,6 +15,14 @@ mysql: maxIdleConn: 10 # 连接的生命时长 connMaxLifetime: 236 +Mail: + user: xx@163.com + alias: xx + pass: + Host: smtp.163.com + Port: 465 + Ssl: true + # 最近文章缓存时间 recentPostCacheTime: 5m # 分类缓存时间 diff --git a/go.mod b/go.mod index 211730a..563dcb3 100644 --- a/go.mod +++ b/go.mod @@ -34,4 +34,6 @@ require ( golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect ) diff --git a/mail/mail.go b/mail/mail.go new file mode 100644 index 0000000..80dd781 --- /dev/null +++ b/mail/mail.go @@ -0,0 +1,56 @@ +package mail + +import ( + "crypto/tls" + "fmt" + "github/fthvgb1/wp-go/vars" + "gopkg.in/gomail.v2" + "mime" + "strings" +) + +type AttacheFile struct { + Name string + Path string +} + +func (f AttacheFile) GetName() string { + t := strings.Split(f.Path, ".") + return fmt.Sprintf("%s.%s", f.Name, t[len(t)-1]) +} + +func SendMail(mailTo []string, subject string, body string, a ...AttacheFile) error { + m := gomail.NewMessage( + gomail.SetEncoding(gomail.Base64), + ) + m.SetHeader("From", + m.FormatAddress(vars.Conf.Mail.User, + vars.Conf.Mail.Alias, + )) + m.SetHeader("To", mailTo...) + m.SetHeader("Subject", subject) + m.SetBody("text/html", body) + + for _, files := range a { + m.Attach(files.Path, + gomail.Rename(files.Name), //重命名 + gomail.SetHeader(map[string][]string{ + "Content-Disposition": { + fmt.Sprintf(`attachment; filename="%s"`, mime.QEncoding.Encode("UTF-8", files.GetName())), + }, + }), + ) + } + + d := gomail.NewDialer( + vars.Conf.Mail.Host, + vars.Conf.Mail.Port, + vars.Conf.Mail.User, + vars.Conf.Mail.Pass, + ) + if vars.Conf.Mail.Ssl { + d.TLSConfig = &tls.Config{InsecureSkipVerify: true} + } + err := d.DialAndSend(m) + return err +} diff --git a/mail/mail_test.go b/mail/mail_test.go new file mode 100644 index 0000000..9d3fa01 --- /dev/null +++ b/mail/mail_test.go @@ -0,0 +1,43 @@ +package mail + +import ( + "github/fthvgb1/wp-go/vars" + "testing" +) + +func TestSendMail(t *testing.T) { + vars.InitConfig() + type args struct { + mailTo []string + subject string + body string + a []AttacheFile + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "t1", + args: args{ + mailTo: []string{"fthvgb1@163.com"}, + subject: "测试发邮件", + body: "测试发邮件", + a: []AttacheFile{ + { + Name: "附件", + Path: "/home/xing/Downloads/favicon.ico", + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := SendMail(tt.args.mailTo, tt.args.subject, tt.args.body, tt.args.a...); (err != nil) != tt.wantErr { + t.Errorf("SendMail() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/middleware/searchlimit.go b/middleware/searchlimit.go index ca17c7e..52a52cd 100644 --- a/middleware/searchlimit.go +++ b/middleware/searchlimit.go @@ -5,7 +5,7 @@ import "github.com/gin-gonic/gin" func SearchLimit(num int64) func(ctx *gin.Context) { fn := IpLimit(num) return func(c *gin.Context) { - if "/" == c.FullPath() && c.Query("s") != "" { + if c.Query("s") != "" { fn(c) } else { c.Next() diff --git a/middleware/sendmail.go b/middleware/sendmail.go new file mode 100644 index 0000000..f9e1f2e --- /dev/null +++ b/middleware/sendmail.go @@ -0,0 +1,139 @@ +package middleware + +import ( + "bytes" + "fmt" + "github.com/gin-gonic/gin" + "github/fthvgb1/wp-go/logs" + "github/fthvgb1/wp-go/mail" + "github/fthvgb1/wp-go/models" + "github/fthvgb1/wp-go/vars" + "io" + "io/ioutil" + "net/http" + "net/http/httputil" + "runtime" + "strings" + "time" +) + +func RecoverAndSendMail(w io.Writer) func(ctx *gin.Context) { + return gin.CustomRecoveryWithWriter(w, func(ctx *gin.Context, err any) { + c := ctx.Copy() + stack := stack(4) + go func() { + httpRequest, _ := httputil.DumpRequest(c.Request, true) + headers := strings.Split(string(httpRequest), "\r\n") + for idx, header := range headers { + current := strings.Split(header, ":") + if current[0] == "Authorization" { + headers[idx] = current[0] + ": *" + } + } + headersToStr := strings.Join(headers, "
") + content := `
err:
%v

+
stack:
%v

+
headers:
%s
+` + content = fmt.Sprintf(content, + err, + formatStack(string(stack)), + headersToStr, + ) + + er := mail.SendMail( + []string{vars.Conf.Mail.User}, + fmt.Sprintf("%s%s %s 发生错误", fmt.Sprintf(models.Options["siteurl"]), c.FullPath(), time.Now().Format(time.RFC1123Z)), content) + + if er != nil { + logs.ErrPrintln(er, "recover send mail fail", fmt.Sprintf("%v", err)) + } + }() + ctx.AbortWithStatus(http.StatusInternalServerError) + }) +} + +var ( + dunno = []byte("???") + centerDot = []byte("·") + dot = []byte(".") + slash = []byte("/") +) + +func formatStack(s string) (r string) { + ss := strings.Builder{} + t := strings.Split(s, "\n") + for i, line := range t { + if i%2 == 0 { + ss.WriteString("
") + ss.WriteString(line) + ss.WriteString("
") + } else { + ss.WriteString("
") + ss.WriteString(strings.Trim(line, "\t")) + ss.WriteString("
") + } + } + r = ss.String() + return +} + +func stack(skip int) []byte { + buf := new(bytes.Buffer) // the returned data + // As we loop, we open files and read them. These variables record the currently + // loaded file. + var lines [][]byte + var lastFile string + for i := skip; ; i++ { // Skip the expected number of frames + pc, file, line, ok := runtime.Caller(i) + if !ok { + break + } + // Print this much at least. If we can't find the source, it won't show. + fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) + if file != lastFile { + data, err := ioutil.ReadFile(file) + if err != nil { + continue + } + lines = bytes.Split(data, []byte{'\n'}) + lastFile = file + } + fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line)) + } + return buf.Bytes() +} + +// function returns, if possible, the name of the function containing the PC. +func function(pc uintptr) []byte { + fn := runtime.FuncForPC(pc) + if fn == nil { + return dunno + } + name := []byte(fn.Name()) + // The name includes the path name to the package, which is unnecessary + // since the file name is already included. Plus, it has center dots. + // That is, we see + // runtime/debug.*T·ptrmethod + // and want + // *T.ptrmethod + // Also the package path might contain dot (e.g. code.google.com/...), + // so first eliminate the path prefix + if lastSlash := bytes.LastIndex(name, slash); lastSlash >= 0 { + name = name[lastSlash+1:] + } + if period := bytes.Index(name, dot); period >= 0 { + name = name[period+1:] + } + name = bytes.Replace(name, centerDot, dot, -1) + return name +} + +// source returns a space-trimmed slice of the n'th line. +func source(lines [][]byte, n int) []byte { + n-- // in stack trace, lines are 1-indexed but our array is 0-indexed + if n < 0 || n >= len(lines) { + return dunno + } + return bytes.TrimSpace(lines[n]) +} diff --git a/route/route.go b/route/route.go index 51340a5..38626f7 100644 --- a/route/route.go +++ b/route/route.go @@ -39,7 +39,7 @@ func SetupRouter() *gin.Engine { r.Use( middleware.ValidateServerNames(), gin.Logger(), - gin.Recovery(), + middleware.RecoverAndSendMail(gin.DefaultErrorWriter), middleware.FlowLimit(vars.Conf.MaxRequestSleepNum, vars.Conf.MaxRequestNum, vars.Conf.SleepTime), middleware.SetStaticFileCache, ) diff --git a/static/wp-includes/css/googleapicss.css b/static/wp-includes/css/googleapicss.css new file mode 100644 index 0000000..844efb7 --- /dev/null +++ b/static/wp-includes/css/googleapicss.css @@ -0,0 +1,600 @@ +/* vietnamese */ +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/inconsolata/v31/QlddNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLyxq15Mjs.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/inconsolata/v31/QlddNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLyx615Mjs.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/inconsolata/v31/QlddNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLyya15.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* vietnamese */ +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/inconsolata/v31/QlddNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLyxq15Mjs.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/inconsolata/v31/QlddNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLyx615Mjs.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/inconsolata/v31/QlddNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLyya15.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0OIpQlx3QUlC5A4PNr4ARPQ_m87A.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0OIpQlx3QUlC5A4PNr4ARGQ_m87A.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* devanagari */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0OIpQlx3QUlC5A4PNr4ARDQ_m87A.woff2) format('woff2'); + unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB; +} +/* greek-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0OIpQlx3QUlC5A4PNr4AROQ_m87A.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0OIpQlx3QUlC5A4PNr4ARBQ_m87A.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0OIpQlx3QUlC5A4PNr4ARNQ_m87A.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0OIpQlx3QUlC5A4PNr4ARMQ_m87A.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0OIpQlx3QUlC5A4PNr4ARCQ_k.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0TIpQlx3QUlC5A4PNr4Az5ZuyOzW1aPQ.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0TIpQlx3QUlC5A4PNr4Az5ZuyHzW1aPQ.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* devanagari */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0TIpQlx3QUlC5A4PNr4Az5ZuyCzW1aPQ.woff2) format('woff2'); + unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB; +} +/* greek-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0TIpQlx3QUlC5A4PNr4Az5ZuyPzW1aPQ.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0TIpQlx3QUlC5A4PNr4Az5ZuyAzW1aPQ.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0TIpQlx3QUlC5A4PNr4Az5ZuyMzW1aPQ.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0TIpQlx3QUlC5A4PNr4Az5ZuyNzW1aPQ.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0TIpQlx3QUlC5A4PNr4Az5ZuyDzW0.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNr6DRAW_0.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNr4TRAW_0.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* devanagari */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNr5DRAW_0.woff2) format('woff2'); + unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB; +} +/* greek-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNr6TRAW_0.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNr5jRAW_0.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNr6jRAW_0.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNr6zRAW_0.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNr5TRA.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0NIpQlx3QUlC5A4PNjXhFVadyB1Wk.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0NIpQlx3QUlC5A4PNjXhFVYNyB1Wk.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* devanagari */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0NIpQlx3QUlC5A4PNjXhFVZdyB1Wk.woff2) format('woff2'); + unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB; +} +/* greek-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0NIpQlx3QUlC5A4PNjXhFVaNyB1Wk.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0NIpQlx3QUlC5A4PNjXhFVZ9yB1Wk.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0NIpQlx3QUlC5A4PNjXhFVa9yB1Wk.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0NIpQlx3QUlC5A4PNjXhFVatyB1Wk.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notosans/v27/o-0NIpQlx3QUlC5A4PNjXhFVZNyB.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Kaw1J5X9T9RW6j9bNfFImZzC7TMQ.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Kaw1J5X9T9RW6j9bNfFImbjC7TMQ.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Kaw1J5X9T9RW6j9bNfFImZjC7TMQ.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Kaw1J5X9T9RW6j9bNfFImaTC7TMQ.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Kaw1J5X9T9RW6j9bNfFImZTC7TMQ.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Kaw1J5X9T9RW6j9bNfFImZDC7TMQ.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Kaw1J5X9T9RW6j9bNfFImajC7.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Vaw1J5X9T9RW6j9bNfFIu0RWufuVMCoY.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Vaw1J5X9T9RW6j9bNfFIu0RWud-VMCoY.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Vaw1J5X9T9RW6j9bNfFIu0RWuf-VMCoY.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Vaw1J5X9T9RW6j9bNfFIu0RWucOVMCoY.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Vaw1J5X9T9RW6j9bNfFIu0RWufOVMCoY.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Vaw1J5X9T9RW6j9bNfFIu0RWufeVMCoY.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Noto Serif'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Vaw1J5X9T9RW6j9bNfFIu0RWuc-VM.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Iaw1J5X9T9RW6j9bNfFoWaCi_.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Iaw1J5X9T9RW6j9bNfFMWaCi_.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Iaw1J5X9T9RW6j9bNfFsWaCi_.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Iaw1J5X9T9RW6j9bNfFQWaCi_.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Iaw1J5X9T9RW6j9bNfFgWaCi_.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Iaw1J5X9T9RW6j9bNfFkWaCi_.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Iaw1J5X9T9RW6j9bNfFcWaA.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Law1J5X9T9RW6j9bNdOwzfRqecf1I.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Law1J5X9T9RW6j9bNdOwzfROecf1I.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Law1J5X9T9RW6j9bNdOwzfRuecf1I.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Law1J5X9T9RW6j9bNdOwzfRSecf1I.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Law1J5X9T9RW6j9bNdOwzfRiecf1I.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Law1J5X9T9RW6j9bNdOwzfRmecf1I.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Noto Serif'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(https://fonts.gstatic.com/s/notoserif/v21/ga6Law1J5X9T9RW6j9bNdOwzfReecQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} \ No newline at end of file diff --git a/vars/config.go b/vars/config.go index f9e7050..123d894 100644 --- a/vars/config.go +++ b/vars/config.go @@ -11,6 +11,7 @@ var Conf Config type Config struct { Mysql Mysql `yaml:"mysql"` + Mail Mail `yaml:"mail"` RecentPostCacheTime time.Duration `yaml:"recentPostCacheTime"` CategoryCacheTime time.Duration `yaml:"categoryCacheTime"` ArchiveCacheTime time.Duration `yaml:"archiveCacheTime"` @@ -37,6 +38,15 @@ type Config struct { TrustServerNames []string `yaml:"trustServerNames"` } +type Mail struct { + User string `yaml:"user"` + Alias string `yaml:"alias"` + Pass string `yaml:"pass"` + Host string `yaml:"host"` + Port int `yaml:"port"` + Ssl bool `yaml:"ssl"` +} + type Mysql struct { Dsn Dsn `yaml:"dsn"` Pool Pool `yaml:"pool"`