update: better CSS border colors

This commit is contained in:
ngn 2024-08-13 22:25:36 +03:00
parent b24a970962
commit 4641faefc2
21 changed files with 873 additions and 445 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
docker-compose.yml
compose.yml
security security
db/ db/

9
Makefile Normal file
View File

@ -0,0 +1,9 @@
all: security
security: */*.go *.go
go build -o $@
format:
gofmt -s -w .
.PHONY: format

View File

@ -1,18 +1,32 @@
# security | MatterLinux Security Tracker # security | MatterLinux security tracker
Soruce code of MatterLinux's security tracker, located at Soruce code of MatterLinux's security tracker, located at
[security.matterlinux.xyz](https://security.matterlinux.xyz) [security.matterlinux.xyz](https://security.matterlinux.xyz)
### Deployment ### Deployment
Web server can be built and deployed with docker: Web server can be built and deployed with docker compose, here is an
example configuration:
```yaml
version: "3"
services:
security:
image: mattersecurity
restart: unless-stopped
build:
context: ./
ports:
- "127.0.0.1:9876:9876"
volumes:
- "./db:/app/db"
```
After saving the configuration file, you can build and run the docker container:
```bash ```bash
docker build --tag mattersecurity .
mkdir -pv db
docker-compose up -d docker-compose up -d
``` ```
### Adding users ### Adding users
After running the application at least once, you can users using After running the application at least once, you can users using
the `adduser.sh` script. This script will add the specified user with a the `adduser.sh` script. This script will add the specified user with a
randomly generated passwords to the sqlite database. For example: randomly generated passwords to the sqlite database. For example:
```bash ```bash
./adduser.sh ngn ./adduser.sh ngn

View File

@ -1,12 +0,0 @@
version: "3"
services:
security:
image: mattersecurity
restart: unless-stopped
build:
context: ./
ports:
- "127.0.0.1:9876:9876"
volumes:
- "./db:/app/db"

View File

@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
var Db *sql.DB var Db *sql.DB
@ -35,34 +35,32 @@ const create_vulns string = `
` `
func LoadDatabase() error { func LoadDatabase() error {
_, err := os.Stat("db") _, err := os.Stat("db")
if err != nil && os.IsNotExist(err) { if err != nil && os.IsNotExist(err) {
err = os.Mkdir("db", os.ModePerm) err = os.Mkdir("db", os.ModePerm)
if err != nil { if err != nil {
return err return err
} }
} }
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return fmt.Errorf("cannot access to db directory") return fmt.Errorf("cannot access to db directory")
} }
Db, err = sql.Open("sqlite3", "db/data.db") Db, err = sql.Open("sqlite3", "db/data.db")
if err != nil { if err != nil {
return err return err
} }
_, err = Db.Exec(create_users) _, err = Db.Exec(create_users)
if err != nil { if err != nil {
return err return err
} }
_, err = Db.Exec(create_vulns) _, err = Db.Exec(create_vulns)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }

33
lib/lib/config.go Normal file
View File

@ -0,0 +1,33 @@
package lib
import (
"encoding/json"
"os"
)
type Config struct {
Pools []Pool `json:"pools"`
}
func (c *Config) Load(list *[]Package, file string) error {
var (
content []byte
err error
)
if content, err = os.ReadFile(file); err != nil {
return err
}
if err = json.Unmarshal(content, c); err != nil {
return err
}
for _, p := range c.Pools {
if err = p.Load(list); err != nil {
return err
}
}
return nil
}

135
lib/lib/package.go Normal file
View File

@ -0,0 +1,135 @@
package lib
import (
"archive/tar"
"bufio"
"compress/gzip"
"fmt"
"io"
"net/url"
"os"
"path"
"strings"
"git.matterlinux.xyz/matter/tracker/log"
"github.com/bigkevmcd/go-configparser"
)
type Package struct {
Name string `json:"name"`
Pool *Pool `json:"-"`
Version string `json:"version"`
Depends []string `json:"depends"`
Size string `json:"size"`
Desc string `json:"desc"`
Archive string `json:"archive"`
}
func (p *Package) Files() []string {
var (
gzip_reader io.Reader
header *tar.Header
result []string
file *os.File
err error
)
if file, err = os.Open(p.Archive); err != nil {
log.Error("Failed to open %s", p.Archive)
return result
}
defer file.Close()
if gzip_reader, err = gzip.NewReader(bufio.NewReader(file)); err != nil {
log.Error("Failed to create reader for %s", p.Archive)
return result
}
reader := tar.NewReader(gzip_reader)
for header, err = reader.Next(); err == nil; header, err = reader.Next() {
if header.Typeflag != tar.TypeReg {
continue
}
if path.Base(header.Name) != "files.tar.gz" {
continue
}
if result, err = GetFiles(reader); err == nil {
break
}
log.Error("Failed to get file list for %s: %s", p.Archive, err.Error())
return []string{}
}
return result
}
func (p *Package) URL() string {
if nil == p.Pool {
return ""
}
url, _ := url.JoinPath(p.Pool.Source, "src/branch/"+p.Pool.Branch+"/src", p.Name)
return url
}
func (p *Package) DependsToStr() string {
var depends string = ""
for _, d := range p.Depends {
depends += fmt.Sprintf("%s ", d)
}
return depends
}
func (p *Package) Load(r io.Reader) error {
var (
err error
size int64
depends string = ""
section string = "DEFAULT"
)
parser := configparser.New()
if err = parser.ParseReader(r); err != nil {
return err
}
for _, s := range parser.Sections() {
if s == "DEFAULT" {
continue
}
section = s
break
}
if section == "DEFAULT" {
return fmt.Errorf("DATA does not contain any sections")
}
p.Name = section
if p.Version, err = parser.Get(section, "version"); err != nil {
return err
}
if size, err = parser.GetInt64(section, "size"); err != nil {
return err
}
p.Size = SizeFromBytes(size)
if p.Desc, err = parser.Get(section, "desc"); err != nil {
return err
}
depends, _ = parser.Get(section, "depends")
if depends == "" {
p.Depends = []string{}
} else {
p.Depends = strings.Split(depends, ",")
}
return nil
}

145
lib/lib/pool.go Normal file
View File

@ -0,0 +1,145 @@
package lib
import (
"archive/tar"
"bufio"
"compress/gzip"
"fmt"
"io"
"os"
"path"
"github.com/bigkevmcd/go-configparser"
)
type Pool struct {
Maintainer string `json:"-"`
Pubkey string `json:"-"`
Size string `json:"-"`
Display string `json:"display"`
Branch string `json:"branch"`
Source string `json:"source"`
Name string `json:"name"`
URL string `json:"url"`
Dir string `json:"dir"`
}
func (p *Pool) Load(list *[]Package) error {
var err error
if p.Dir == "" {
return fmt.Errorf("pool directory is not specified")
}
if err = p.LoadInfo(); err != nil {
return err
}
if err = p.LoadList(list); err != nil {
return err
}
return nil
}
func (p *Pool) LoadList(list *[]Package) error {
var (
list_path string
list_file *os.File
gzip_reader io.Reader
header *tar.Header
err error
)
list_path = path.Join(p.Dir, "LIST")
if list_file, err = os.Open(list_path); err != nil {
return err
}
defer list_file.Close()
if gzip_reader, err = gzip.NewReader(bufio.NewReader(list_file)); err != nil {
return err
}
reader := tar.NewReader(gzip_reader)
for header, err = reader.Next(); err == nil; header, err = reader.Next() {
if header.Typeflag != tar.TypeReg {
continue
}
if path.Base(header.Name) != "DATA" {
return fmt.Errorf("LIST archive contains an unknown file")
}
var pkg Package
if err = pkg.Load(reader); err != nil {
return err
}
pkg.Archive = path.Join(p.Dir, fmt.Sprintf("%s_%s.mpf", pkg.Name, pkg.Version))
pkg.Pool = p
*list = append(*list, pkg)
}
return nil
}
func (p *Pool) LoadInfo() error {
var (
info_path string
info_file *os.File
section string
size int64
err error
)
info_path = path.Join(p.Dir, "INFO")
if info_file, err = os.Open(info_path); err != nil {
return err
}
parser := configparser.New()
if err = parser.ParseReader(bufio.NewReader(info_file)); err != nil {
return err
}
section = "DEFAULT"
for _, s := range parser.Sections() {
if s == "DEFAULT" {
continue
}
section = s
break
}
if section == "DEFAULT" {
return fmt.Errorf("DATA does not contain any sections")
}
if p.Name != section {
return fmt.Errorf("pool name (\"%s\") doesn't match with \"%s\"", p.Name, section)
}
if p.Maintainer, err = parser.Get(p.Name, "maintainer"); err != nil {
return err
}
if size, err = parser.GetInt64(section, "size"); err != nil {
return err
}
p.Size = SizeFromBytes(size)
if p.Pubkey, err = parser.Get(section, "pubkey"); err != nil {
return err
}
return nil
}

104
lib/lib/util.go Normal file
View File

@ -0,0 +1,104 @@
package lib
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"strings"
"time"
"github.com/gofiber/fiber/v2"
)
func GetFiles(r io.Reader) ([]string, error) {
var (
gzip_reader io.Reader
header *tar.Header
result []string
err error
)
if gzip_reader, err = gzip.NewReader(r); err != nil {
return result, err
}
reader := tar.NewReader(gzip_reader)
for header, err = reader.Next(); err == nil; header, err = reader.Next() {
if header.Typeflag != tar.TypeReg {
continue
}
result = append(result, header.Name)
}
return result, nil
}
func ListToStr(l []string) string {
res := ""
for _, e := range l {
res += e + " "
}
return res
}
func RenderError(c *fiber.Ctx, code int) error {
var msg string = "Server Error"
c.Status(code)
switch code {
case 404:
msg = "Not Found"
}
return c.Render("error", fiber.Map{
"msg": msg,
})
}
func SizeFromBytes(size int64) string {
if size > 1024*1024*1024 {
return fmt.Sprintf("%dGB", (size / 1024 / 1024 / 1024))
} else if size > 1024*1024 {
return fmt.Sprintf("%dMB", (size / 1024 / 1024))
} else if size > 1024 {
return fmt.Sprintf("%dKB", (size / 1024))
}
return fmt.Sprintf("%dB", size)
}
func TimePassed(t time.Time) string {
diff := time.Since(t)
res := fmt.Sprintf(
"%ds ago",
int(diff.Seconds()),
)
if diff.Minutes() > 1 {
res = fmt.Sprintf(
"%dm and %ds ago",
int(diff.Minutes()), int(diff.Seconds())-(int(diff.Minutes())*60),
)
}
if diff.Hours() > 1 {
res = fmt.Sprintf("%dh and %dm ago",
int(diff.Hours()),
int(diff.Minutes())-(int(diff.Hours())*60),
)
}
return res
}
func SanitizeXSS(s string) string {
var bad []string = []string{"~", "'", "\"", "/", "<", ">", "?", "=", "#", "(", ")", "{", "}", "*", "!", "`", "[", "]"}
for _, c := range bad {
s = strings.ReplaceAll(s, c, "")
}
return s
}

View File

@ -7,54 +7,54 @@ import (
) )
type User struct { type User struct {
Username string Username string
Password string Password string
Cookie string Cookie string
} }
func GetUser(c *fiber.Ctx) (User, error) { func GetUser(c *fiber.Ctx) (User, error) {
users, err := LoadUsers() users, err := LoadUsers()
if err != nil { if err != nil {
return User{}, err return User{}, err
} }
for i, u := range users { for i, u := range users {
if c.Cookies("auth") == u.Cookie { if c.Cookies("auth") == u.Cookie {
return users[i], nil return users[i], nil
} }
} }
return User{}, fmt.Errorf("user not found") return User{}, fmt.Errorf("user not found")
} }
func LoadUsers() ([]User, error) { func LoadUsers() ([]User, error) {
var users []User var users []User
rows, err := Db.Query("SELECT * FROM users")
if err != nil {
return users, err
}
defer rows.Close()
for rows.Next() { rows, err := Db.Query("SELECT * FROM users")
var u User if err != nil {
rows.Scan(&u.Username, &u.Password, &u.Cookie) return users, err
users = append(users, u) }
} defer rows.Close()
return users, nil for rows.Next() {
var u User
rows.Scan(&u.Username, &u.Password, &u.Cookie)
users = append(users, u)
}
return users, nil
} }
func UpdateUser(u User) error { func UpdateUser(u User) error {
smt, err := Db.Prepare("UPDATE users SET password=?, cookie=? WHERE username=?") smt, err := Db.Prepare("UPDATE users SET password=?, cookie=? WHERE username=?")
if err != nil { if err != nil {
return err return err
} }
_, err = smt.Exec(u.Password, u.Cookie, u.Username) _, err = smt.Exec(u.Password, u.Cookie, u.Username)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }

View File

@ -12,46 +12,46 @@ import (
) )
func GetFTime() string { func GetFTime() string {
return time.Now().Format("01/02/2006") return time.Now().Format("01/02/2006")
} }
func GetRandom() string { func GetRandom() string {
buf := make([]byte, 128) buf := make([]byte, 128)
_, err := rand.Read(buf) _, err := rand.Read(buf)
if err != nil { if err != nil {
log.Fatalf("Failed to get random bytes: %s", err.Error()) log.Fatalf("Failed to get random bytes: %s", err.Error())
} }
return GetSHA256(buf) return GetSHA256(buf)
} }
func GetSHA256(s []byte) string { func GetSHA256(s []byte) string {
sum := sha256.Sum256(s) sum := sha256.Sum256(s)
return fmt.Sprintf("%x", sum) return fmt.Sprintf("%x", sum)
} }
func ContainsCase(s1 string, s2 string) bool { func ContainsCase(s1 string, s2 string) bool {
return strings.Contains( return strings.Contains(
strings.ToLower(s1), strings.ToLower(s2), strings.ToLower(s1), strings.ToLower(s2),
) )
} }
func RenderError(c *fiber.Ctx, code int) error{ func RenderError(c *fiber.Ctx, code int) error {
var msg string = "Server Error" var msg string = "Server Error"
c.Status(code) c.Status(code)
switch code { switch code {
case 404: case 404:
msg = "Not Found" msg = "Not Found"
case 500: case 500:
msg = "Server error" msg = "Server error"
case 403: case 403:
msg = "Forbidden" msg = "Forbidden"
case 400: case 400:
msg = "Bad request" msg = "Bad request"
} }
return c.Render("error", fiber.Map{ return c.Render("error", fiber.Map{
"msg": msg, "msg": msg,
}) })
} }

View File

@ -7,131 +7,131 @@ import (
) )
type Vuln struct { type Vuln struct {
ID string ID string
Desc string Desc string
Source string Source string
Severity string Severity string
Package string Package string
Versions string Versions string
Status string Status string
Message string Message string
Author string Author string
Date string Date string
Updated string Updated string
} }
func ValidSeverity(s string) bool { func ValidSeverity(s string) bool {
switch s { switch s {
case "Low": case "Low":
return true return true
case "Medium": case "Medium":
return true return true
case "High": case "High":
return true return true
case "Critical": case "Critical":
return true return true
} }
return false return false
} }
func (v Vuln) StatusColor() string { func (v Vuln) StatusColor() string {
switch v.Status { switch v.Status {
case "Waiting for review": case "Waiting for review":
return "blue" return "blue"
case "Ongoing review": case "Ongoing review":
return "blue" return "blue"
case "Working on a patch": case "Working on a patch":
return "blue" return "blue"
case "Won't patch": case "Won't patch":
return "red" return "red"
case "Patched": case "Patched":
return "green" return "green"
case "Not affected": case "Not affected":
return "red" return "red"
} }
return "" return ""
} }
func GetID() string { func GetID() string {
now := time.Now() now := time.Now()
mic := strconv.FormatInt(now.UnixMicro(), 10) mic := strconv.FormatInt(now.UnixMicro(), 10)
sig := GetSHA256([]byte(mic))[:5] sig := GetSHA256([]byte(mic))[:5]
return fmt.Sprintf( return fmt.Sprintf(
"MPSI-%s%s-%s", "MPSI-%s%s-%s",
now.Format("06"), now.Format("01"), sig, now.Format("06"), now.Format("01"), sig,
) )
} }
func LoadVulns() ([]Vuln, error) { func LoadVulns() ([]Vuln, error) {
var vulns []Vuln var vulns []Vuln
rows, err := Db.Query("SELECT * FROM vulns")
if err != nil {
return vulns, err
}
defer rows.Close()
for rows.Next() { rows, err := Db.Query("SELECT * FROM vulns")
var v Vuln if err != nil {
rows.Scan( return vulns, err
&v.ID, &v.Desc, &v.Source, &v.Severity, }
&v.Package, &v.Versions, &v.Status, &v.Message, defer rows.Close()
&v.Author, &v.Date, &v.Updated)
vulns = append(vulns, v) for rows.Next() {
} var v Vuln
rows.Scan(
return vulns, nil &v.ID, &v.Desc, &v.Source, &v.Severity,
&v.Package, &v.Versions, &v.Status, &v.Message,
&v.Author, &v.Date, &v.Updated)
vulns = append(vulns, v)
}
return vulns, nil
} }
func FindVuln(id string) (Vuln, bool) { func FindVuln(id string) (Vuln, bool) {
var vuln Vuln var vuln Vuln
smt, err := Db.Prepare("SELECT * FROM vulns WHERE id=?") smt, err := Db.Prepare("SELECT * FROM vulns WHERE id=?")
if err != nil { if err != nil {
return vuln, false return vuln, false
} }
row := smt.QueryRow(id) row := smt.QueryRow(id)
err = row.Scan( err = row.Scan(
&vuln.ID, &vuln.Desc, &vuln.Source, &vuln.Severity, &vuln.ID, &vuln.Desc, &vuln.Source, &vuln.Severity,
&vuln.Package, &vuln.Versions, &vuln.Status, &vuln.Message, &vuln.Package, &vuln.Versions, &vuln.Status, &vuln.Message,
&vuln.Author, &vuln.Date, &vuln.Updated) &vuln.Author, &vuln.Date, &vuln.Updated)
if err != nil { if err != nil {
return vuln, false return vuln, false
} }
return vuln, true return vuln, true
} }
func AddVuln(v Vuln) error{ func AddVuln(v Vuln) error {
smt, err := Db.Prepare("INSERT INTO vulns VALUES(?,?,?,?,?,?,?,?,?,?,?)") smt, err := Db.Prepare("INSERT INTO vulns VALUES(?,?,?,?,?,?,?,?,?,?,?)")
if err != nil { if err != nil {
return err return err
} }
_, err = smt.Exec(&v.ID, &v.Desc, &v.Source, &v.Severity, _, err = smt.Exec(&v.ID, &v.Desc, &v.Source, &v.Severity,
&v.Package, &v.Versions, &v.Status, &v.Message, &v.Package, &v.Versions, &v.Status, &v.Message,
&v.Author, &v.Date, &v.Updated) &v.Author, &v.Date, &v.Updated)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
func UpdateVuln(v Vuln) error { func UpdateVuln(v Vuln) error {
smt, err := Db.Prepare("UPDATE vulns SET status=?, message=?, author=?, severity=?, updated=? WHERE id=?") smt, err := Db.Prepare("UPDATE vulns SET status=?, message=?, author=?, severity=?, updated=? WHERE id=?")
if err != nil { if err != nil {
return err return err
} }
_, err = smt.Exec(v.Status, v.Message, _, err = smt.Exec(v.Status, v.Message,
v.Author, v.Severity, GetFTime(), v.ID) v.Author, v.Severity, GetFTime(), v.ID)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }

62
main.go
View File

@ -1,7 +1,7 @@
/* /*
* security | MatterLinux Package Security Tracker * security | MatterLinux Package Security Tracker
* MatterLinux 2023-2024 (https://matterlinux.xyz) * MatterLinux 2023-2024 (https://matterlinux.xyz)
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package main package main
@ -30,39 +30,39 @@ import (
) )
func main() { func main() {
log.SetFlags(log.Lshortfile | log.Ltime) log.SetFlags(log.Lshortfile | log.Ltime)
engine := html.New("./templates", ".html") engine := html.New("./templates", ".html")
app := fiber.New(fiber.Config{ app := fiber.New(fiber.Config{
DisableStartupMessage: true, DisableStartupMessage: true,
Views: engine, Views: engine,
}) })
err := lib.LoadDatabase() err := lib.LoadDatabase()
if err != nil { if err != nil {
log.Fatalf("Failed to load database: %s", err.Error()) log.Fatalf("Failed to load database: %s", err.Error())
} }
app.Static("/", "./public") app.Static("/", "./public")
app.Get("/", routes.GETIndex) app.Get("/", routes.GETIndex)
app.Get("/details/:id", routes.GETDetails) app.Get("/details/:id", routes.GETDetails)
app.Get("/login", routes.GETLogin) app.Get("/login", routes.GETLogin)
app.Post("/login", routes.POSTLogin) app.Post("/login", routes.POSTLogin)
app.Use("/manage", routes.MiddleAuth) app.Use("/manage", routes.MiddleAuth)
app.Get("/manage", routes.GETManage) app.Get("/manage", routes.GETManage)
app.Get("/manage/logout", routes.GETLogout) app.Get("/manage/logout", routes.GETLogout)
app.Post("/manage/new", routes.POSTNew) app.Post("/manage/new", routes.POSTNew)
app.Post("/manage/status", routes.POSTStatus) app.Post("/manage/status", routes.POSTStatus)
app.Get("*", func(c *fiber.Ctx) error { app.Get("*", func(c *fiber.Ctx) error {
return lib.RenderError(c, 404) return lib.RenderError(c, 404)
}) })
log.Printf("Starting MatterLinux Security Tracker on port 9876") log.Printf("Starting MatterLinux Security Tracker on port 9876")
err = app.Listen(":9876") err = app.Listen(":9876")
if err != nil { if err != nil {
log.Fatalf("Error starting server: %s", err) log.Fatalf("Error starting server: %s", err)
} }
} }

View File

@ -1,7 +1,7 @@
.vuln { .vuln {
padding: 30px; padding: 30px;
background: var(--dark-second); background: var(--dark-second);
border: solid 1px var(--bright-main); border: solid 1px var(--bright-second);
color: var(--bright-second); color: var(--bright-second);
} }
@ -113,7 +113,7 @@
gap: 10px; gap: 10px;
background: var(--dark-second); background: var(--dark-second);
border: solid 1px var(--bright-main); border: solid 1px var(--bright-second);
} }
.search-header { .search-header {

View File

@ -1,7 +1,7 @@
form { form {
background: var(--dark-second); background: var(--dark-second);
padding: 30px; padding: 30px;
border: solid 1px var(--bright-main); border: solid 1px var(--bright-second);
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -3,7 +3,7 @@ main a {
flex-direction: column; flex-direction: column;
font-size: 15px; font-size: 15px;
color: var(--bright-main); color: var(--bright-second);
text-align: right; text-align: right;
margin-bottom: 10px; margin-bottom: 10px;
} }
@ -15,7 +15,7 @@ main a:hover {
form { form {
background: var(--dark-second); background: var(--dark-second);
padding: 30px; padding: 30px;
border: solid 1px var(--bright-main); border: solid 1px var(--bright-second);
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -13,78 +13,78 @@ import (
var PAGE_SIZE = 32 var PAGE_SIZE = 32
func GetPage(c *fiber.Ctx) (int, int, int) { func GetPage(c *fiber.Ctx) (int, int, int) {
page, err := strconv.Atoi(c.Query("p")) page, err := strconv.Atoi(c.Query("p"))
if err != nil || page <= 0 { if err != nil || page <= 0 {
page = 1 page = 1
} }
return page, page*PAGE_SIZE, (page*PAGE_SIZE)-PAGE_SIZE return page, page * PAGE_SIZE, (page * PAGE_SIZE) - PAGE_SIZE
} }
func GETDetails(c *fiber.Ctx) error { func GETDetails(c *fiber.Ctx) error {
id := c.Params("id") id := c.Params("id")
if id == "" || !strings.HasPrefix(id, "MPSI-") { if id == "" || !strings.HasPrefix(id, "MPSI-") {
return lib.RenderError(c, 404) return lib.RenderError(c, 404)
} }
v, suc := lib.FindVuln(id) v, suc := lib.FindVuln(id)
if !suc { if !suc {
return lib.RenderError(c, 404) return lib.RenderError(c, 404)
} }
return c.Render("details", fiber.Map{ return c.Render("details", fiber.Map{
"v": v, "v": v,
}) })
} }
func GETIndex(c *fiber.Ctx) error { func GETIndex(c *fiber.Ctx) error {
cur, max, min := GetPage(c) cur, max, min := GetPage(c)
search_qu := c.Query("q") search_qu := c.Query("q")
search_in := c.Query("i") search_in := c.Query("i")
vulns, err := lib.LoadVulns() vulns, err := lib.LoadVulns()
if err != nil { if err != nil {
log.Printf("Failed to load vulns: %s", err.Error()) log.Printf("Failed to load vulns: %s", err.Error())
return lib.RenderError(c, 500) return lib.RenderError(c, 500)
} }
results := []lib.Vuln{} results := []lib.Vuln{}
for i := len(vulns)-1; i >= 0; i-- { for i := len(vulns) - 1; i >= 0; i-- {
if i >= max || i < min { if i >= max || i < min {
continue continue
} }
switch search_in {
case "desc":
if !lib.ContainsCase(vulns[i].Desc, search_qu){
continue
}
case "id":
if !lib.ContainsCase(vulns[i].ID, search_qu) {
continue
}
case "pkg":
if !lib.ContainsCase(vulns[i].Package, search_qu) {
continue
}
case "status":
if !lib.ContainsCase(vulns[i].Status, search_qu) {
continue
}
}
results = append(results, vulns[i]) switch search_in {
case "desc":
if !lib.ContainsCase(vulns[i].Desc, search_qu) {
continue
}
case "id":
if !lib.ContainsCase(vulns[i].ID, search_qu) {
continue
}
case "pkg":
if !lib.ContainsCase(vulns[i].Package, search_qu) {
continue
}
case "status":
if !lib.ContainsCase(vulns[i].Status, search_qu) {
continue
}
}
} results = append(results, vulns[i])
pages := int64(math.Ceil(float64(len(results))/float64(PAGE_SIZE))) }
return c.Render("index", fiber.Map{
"pages": pages, pages := int64(math.Ceil(float64(len(results)) / float64(PAGE_SIZE)))
"current": cur, return c.Render("index", fiber.Map{
"next": cur+1, "pages": pages,
"prev": cur-1, "current": cur,
"vulns": results, "next": cur + 1,
"query": search_qu, "prev": cur - 1,
"in": search_in, "vulns": results,
}) "query": search_qu,
"in": search_in,
})
} }

View File

@ -8,47 +8,47 @@ import (
) )
func POSTLogin(c *fiber.Ctx) error { func POSTLogin(c *fiber.Ctx) error {
body := struct{ body := struct {
Username string `form:"username"` Username string `form:"username"`
Password string `form:"password"` Password string `form:"password"`
}{} }{}
err := c.BodyParser(&body) err := c.BodyParser(&body)
if err != nil { if err != nil {
return lib.RenderError(c, 400) return lib.RenderError(c, 400)
} }
users, err := lib.LoadUsers() users, err := lib.LoadUsers()
if err != nil { if err != nil {
log.Printf("Failed to load users: %s", err.Error()) log.Printf("Failed to load users: %s", err.Error())
return lib.RenderError(c, 500) return lib.RenderError(c, 500)
} }
for _, u := range users { for _, u := range users {
if u.Username == u.Username && if u.Username == u.Username &&
u.Password == lib.GetSHA256([]byte(body.Password)) { u.Password == lib.GetSHA256([]byte(body.Password)) {
u.Cookie = lib.GetRandom() u.Cookie = lib.GetRandom()
c.Cookie(&fiber.Cookie{ c.Cookie(&fiber.Cookie{
Name: "auth", Name: "auth",
Value: u.Cookie, Value: u.Cookie,
}) })
err = lib.UpdateUser(u) err = lib.UpdateUser(u)
if err != nil { if err != nil {
log.Printf("Failed to update user: %s", err.Error()) log.Printf("Failed to update user: %s", err.Error())
return lib.RenderError(c, 500) return lib.RenderError(c, 500)
} }
return c.Redirect("/manage") return c.Redirect("/manage")
} }
} }
c.Status(403) c.Status(403)
return c.Render("login", fiber.Map{}) return c.Render("login", fiber.Map{})
} }
func GETLogin(c *fiber.Ctx) error { func GETLogin(c *fiber.Ctx) error {
if c.Cookies("auth") != "" { if c.Cookies("auth") != "" {
return c.Redirect("/manage") return c.Redirect("/manage")
} }
return c.Render("login", fiber.Map{}) return c.Render("login", fiber.Map{})
} }

View File

@ -8,49 +8,49 @@ import (
) )
func MiddleAuth(c *fiber.Ctx) error { func MiddleAuth(c *fiber.Ctx) error {
cookie := c.Cookies("auth") cookie := c.Cookies("auth")
if cookie == "" { if cookie == "" {
return c.Redirect("/login") return c.Redirect("/login")
} }
users, err := lib.LoadUsers() users, err := lib.LoadUsers()
if err != nil { if err != nil {
log.Printf("Failed to load users: %s", err.Error()) log.Printf("Failed to load users: %s", err.Error())
return lib.RenderError(c, 500) return lib.RenderError(c, 500)
} }
for _, u := range users { for _, u := range users {
if u.Cookie == "notset" || u.Cookie == "" { if u.Cookie == "notset" || u.Cookie == "" {
continue continue
} }
if cookie == u.Cookie { if cookie == u.Cookie {
return c.Next() return c.Next()
} }
} }
c.ClearCookie("auth") c.ClearCookie("auth")
return c.Redirect("/login") return c.Redirect("/login")
} }
func GETManage(c *fiber.Ctx) error { func GETManage(c *fiber.Ctx) error {
return c.Render("manage", fiber.Map{}) return c.Render("manage", fiber.Map{})
} }
func GETLogout(c *fiber.Ctx) error { func GETLogout(c *fiber.Ctx) error {
user, err := lib.GetUser(c) user, err := lib.GetUser(c)
if err != nil { if err != nil {
log.Printf("Failed to load user: %s", err.Error()) log.Printf("Failed to load user: %s", err.Error())
return lib.RenderError(c, 500) return lib.RenderError(c, 500)
} }
user.Cookie = "notset" user.Cookie = "notset"
err = lib.UpdateUser(user) err = lib.UpdateUser(user)
if err != nil { if err != nil {
log.Printf("Failed to save users: %s", err.Error()) log.Printf("Failed to save users: %s", err.Error())
return lib.RenderError(c, 500) return lib.RenderError(c, 500)
} }
return c.Redirect("/login") return c.Redirect("/login")
} }

View File

@ -8,48 +8,48 @@ import (
) )
func POSTNew(c *fiber.Ctx) error { func POSTNew(c *fiber.Ctx) error {
body := struct{ body := struct {
Desc string `form:"desc"` Desc string `form:"desc"`
Source string `form:"source"` Source string `form:"source"`
Severity string `form:"severity"` Severity string `form:"severity"`
Package string `form:"package"` Package string `form:"package"`
Versions string `form:"versions"` Versions string `form:"versions"`
}{} }{}
err := c.BodyParser(&body)
if err != nil {
return lib.RenderError(c, 400)
}
user, err := lib.GetUser(c) err := c.BodyParser(&body)
if err != nil { if err != nil {
log.Printf("Failed to get the user: %s", err.Error()) return lib.RenderError(c, 400)
return lib.RenderError(c, 500) }
}
if !lib.ValidSeverity(body.Severity){ user, err := lib.GetUser(c)
return lib.RenderError(c, 400) if err != nil {
} log.Printf("Failed to get the user: %s", err.Error())
return lib.RenderError(c, 500)
}
v := lib.Vuln{ if !lib.ValidSeverity(body.Severity) {
ID: lib.GetID(), return lib.RenderError(c, 400)
Desc: body.Desc, }
Source: body.Source,
Severity: body.Severity,
Package: body.Package,
Versions: body.Versions,
Status: "Waiting for review",
Message: "This vulnerability is waiting for a review from the maintainers",
Author: user.Username,
Date: lib.GetFTime(),
Updated: lib.GetFTime(),
}
err = lib.AddVuln(v) v := lib.Vuln{
if err != nil { ID: lib.GetID(),
log.Printf("Failed to add vuln: %s", err.Error()) Desc: body.Desc,
return lib.RenderError(c, 500) Source: body.Source,
} Severity: body.Severity,
Package: body.Package,
Versions: body.Versions,
Status: "Waiting for review",
Message: "This vulnerability is waiting for a review from the maintainers",
Author: user.Username,
Date: lib.GetFTime(),
Updated: lib.GetFTime(),
}
return c.Redirect("/manage") err = lib.AddVuln(v)
if err != nil {
log.Printf("Failed to add vuln: %s", err.Error())
return lib.RenderError(c, 500)
}
return c.Redirect("/manage")
} }

View File

@ -10,39 +10,39 @@ import (
) )
func POSTStatus(c *fiber.Ctx) error { func POSTStatus(c *fiber.Ctx) error {
body := struct{ body := struct {
ID string `form:"id"` ID string `form:"id"`
Status string `form:"status"` Status string `form:"status"`
Message string `form:"message"` Message string `form:"message"`
}{} }{}
err := c.BodyParser(&body)
if err != nil {
return lib.RenderError(c, 400)
}
user, err := lib.GetUser(c) err := c.BodyParser(&body)
if err != nil { if err != nil {
log.Printf("Failed to get the user: %s", err.Error()) return lib.RenderError(c, 400)
return lib.RenderError(c, 500) }
}
vuln, suc := lib.FindVuln(body.ID) user, err := lib.GetUser(c)
if !suc { if err != nil {
return lib.RenderError(c, 404) log.Printf("Failed to get the user: %s", err.Error())
} return lib.RenderError(c, 500)
}
vuln.Message = body.Message vuln, suc := lib.FindVuln(body.ID)
vuln.Status = body.Status if !suc {
if vuln.Author != user.Username && !strings.Contains(vuln.Author, ", "+user.Username){ return lib.RenderError(c, 404)
vuln.Author += ", "+user.Username }
}
err = lib.UpdateVuln(vuln) vuln.Message = body.Message
if err != nil { vuln.Status = body.Status
log.Printf("Failed to update the vuln: %s", err.Error()) if vuln.Author != user.Username && !strings.Contains(vuln.Author, ", "+user.Username) {
return lib.RenderError(c, 500) vuln.Author += ", " + user.Username
} }
return c.Redirect("/manage") err = lib.UpdateVuln(vuln)
if err != nil {
log.Printf("Failed to update the vuln: %s", err.Error())
return lib.RenderError(c, 500)
}
return c.Redirect("/manage")
} }