-
-
Save fieu/2056a049de948d2c98394792ae72f8d5 to your computer and use it in GitHub Desktop.
An image/file hosting server written in go - my version of https://gist.github.com/Twister915/d6b5c28753f230fabda3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"github.com/gin-gonic/gin" | |
_ "github.com/lib/pq" | |
"github.com/gorilla/context" | |
"github.com/jinzhu/gorm" | |
"github.com/spf13/viper" | |
"time" | |
"fmt" | |
"os" | |
"net/http" | |
"math/rand" | |
"io/ioutil" | |
"strings" | |
) | |
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") | |
var browsers = []string{"firefox/", "seamonkey/", "chrome/", "chromium/", "safari/", "opera/", "msie"} | |
const ApiKey = 0; | |
func main() { | |
rand.Seed(time.Now().UnixNano()) | |
//Configuration Defaults | |
viper.SetDefault("database", map[string]string{"type": "postgres", "connectionString": "user=lunar password=password dbname=lunar host=localhost sslmode=disable"}) | |
viper.SetDefault("database.user", "lunar") | |
viper.SetDefault("database.password", "password") | |
viper.SetDefault("database.dbname", "lunar") | |
viper.SetDefault("database.sslmode", "disable") | |
viper.SetDefault("url", "http://tjh.im") | |
viper.SetDefault("host", "localhost") | |
viper.SetDefault("port", 81) | |
viper.SetDefault("defaultMessage", "This is my image server. You may be looking for my main website - http://tomharris.me") | |
//Make configuration if it doesn't exist and read it | |
viper.SetConfigName("config") | |
cwd, err := os.Getwd() | |
if err != nil { | |
panic(fmt.Errorf("Couldn't get current working directory: %s\n", err.Error())) | |
} | |
viper.AddConfigPath(cwd) | |
err = viper.ReadInConfig() | |
if err != nil { | |
panic(fmt.Errorf("Couldn't load config: %s \n", err)) | |
} | |
host := viper.GetString("host") | |
port := viper.GetInt("port") | |
siteURL := viper.GetString("url") | |
defaultMessage := viper.GetString("defaultMessage") | |
databaseConfig := viper.GetStringMapString("database") | |
//Connect to database | |
db, err := gorm.Open(databaseConfig["type"], databaseConfig["connectionString"]) | |
if err != nil { | |
panic(fmt.Errorf("Couldn't open database connection: %s \n", err)) | |
} | |
//Set up tables | |
db.AutoMigrate(&APIKey{}, &Upload{}) | |
if len(os.Args) > 1 && (os.Args[1] == "genkey" || os.Args[1] == "genadminkey") { | |
if len(os.Args) == 2 { | |
fmt.Printf("Please provide a description") | |
return | |
} | |
description := "" | |
for index,element := range os.Args { | |
if index > 1 { | |
description += element + " " | |
} | |
} | |
var admin bool | |
if os.Args[1] == "genkey" { | |
admin = false | |
} else | |
if os.Args[1] == "genadminkey" { | |
admin = true | |
} | |
apiKey := APIKey{Key: GenKey(64), Description: description, Admin: admin} | |
db.Create(&apiKey) | |
fmt.Printf("New API key:\n %s\t%t\t%s", apiKey.Key, apiKey.Admin, apiKey.Description) | |
os.Exit(0) | |
} | |
//Set up router | |
router := gin.Default() | |
//Upload file | |
router.POST("/upload", Authenticate(db), func (c *gin.Context) { | |
file, header, err := c.Request.FormFile("file") | |
if err != nil { | |
c.String(http.StatusBadRequest, "Couldn't upload your file: " + err.Error()) | |
return | |
} | |
data, err := ioutil.ReadAll(file) | |
if err != nil { | |
c.String(http.StatusInternalServerError, "Couldn't read your file: " + err.Error()) | |
return | |
} | |
upload := Upload{ID: GenKey(7), Type: header.Header.Get("Content-Type"), Data: data, ApiKey: context.Get(c.Request, ApiKey).(APIKey), Views: 0, UploadedAt: time.Now().UTC()} | |
if upload.Type == "" { | |
c.String(http.StatusBadRequest, "Couldn't find a Content-Type header on your file") | |
return | |
} | |
db.Create(&upload) | |
c.String(http.StatusOK, siteURL + "/" + upload.ID) | |
}) | |
//Get file | |
router.GET("/:id", func (c *gin.Context) { | |
var upload Upload | |
db.Where("id = ?", c.Param("id")).First(&upload) | |
if upload.ID == "" { | |
c.String(http.StatusNotFound, "Couldn't find file") | |
return | |
} | |
upload.Views += 1 | |
db.Save(&upload) | |
outputHeaders := c.Writer.Header() | |
outputHeaders.Add("Content-Type", upload.Type) | |
outputHeaders.Add("Content-Disposition", fmt.Sprintf("inline;filename=\"%s\"", upload.ID)) | |
c.Writer.WriteHeader(http.StatusOK) | |
c.Writer.Write(upload.Data) | |
}) | |
router.GET("/", func (c *gin.Context) { | |
c.String(http.StatusOK, defaultMessage) | |
}) | |
router.Run(fmt.Sprintf("%s:%d", host, port)) | |
} | |
func Authenticate(db gorm.DB) gin.HandlerFunc { | |
return func(c *gin.Context) { | |
var dbKey APIKey | |
key := c.PostForm("key") | |
if key == "" { | |
c.String(http.StatusUnauthorized, "Please provide an API key") | |
c.Abort() | |
return | |
} | |
db.Where(&APIKey{Key: key}).First(&dbKey) | |
if dbKey.Key == "" { | |
c.String(http.StatusUnauthorized, "Invalid API key") | |
c.Abort() | |
return | |
} | |
context.Set(c.Request, ApiKey, dbKey) | |
c.Next() | |
} | |
} | |
func UserAgentIsBrowser(useragent string) bool { | |
useragent = strings.ToLower(useragent) | |
for _,browser := range browsers { | |
if strings.Contains(useragent, browser) { | |
return true | |
} | |
} | |
return false | |
} | |
func GenKey(length int) string { | |
key := make([]rune, length) | |
for i := range key { | |
key[i] = letters[rand.Intn(len(letters))] | |
} | |
return string(key) | |
} | |
type APIKey struct { | |
gorm.Model | |
Key string | |
Description string | |
Admin bool | |
} | |
type Upload struct { | |
ID string `gorm:"primary_key"` | |
Name string | |
Type string | |
Data []byte | |
ApiKey APIKey | |
Views uint | |
UploadedAt time.Time | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment