Skip to content

Instantly share code, notes, and snippets.

@fieu
Forked from msmoode/lunar.go
Created April 14, 2016 20:55
Show Gist options
  • Save fieu/2056a049de948d2c98394792ae72f8d5 to your computer and use it in GitHub Desktop.
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
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