├── .gitignore
├── .gitattributes
├── modules
├── utils.go
├── pages.go
└── api.go
├── app.json
├── html
├── index.html
└── upload.html
├── main.go
├── go.mod
├── README.md
├── .github
└── workflows
│ └── main.yml
└── go.sum
/.gitignore:
--------------------------------------------------------------------------------
1 | downloads
2 | FileServer
3 | FileServer.exe
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/modules/utils.go:
--------------------------------------------------------------------------------
1 | package modules
2 |
3 | import (
4 | "math/rand"
5 | "time"
6 | )
7 |
8 | func RandomString(count int) string {
9 | rand.Seed(time.Now().UnixNano())
10 | letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
11 | b := make([]rune, count)
12 | for i := range b {
13 | b[i] = letters[rand.Intn(len(letters))]
14 | }
15 | return string(b)
16 | }
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "File Server",
3 | "description": "An app that can store files in your server and get links for files",
4 | "repository": "https://github.com/AnjanaMadu/FileServer",
5 | "logo": "https://img.icons8.com/color/48/000000/database-restore.png",
6 | "env": {
7 | "GOVERSION": {
8 | "description": "Dont change this.",
9 | "value": "1.17"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | File Server
7 |
8 | Welcome to File Server v0.1
9 |
10 | This is a simple file server that allows you to upload files to the server.
11 |
12 | You can upload files to the server and then download them.
13 |
14 | Go to Uploads page to upload files!
15 |
16 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 |
6 | "FileServer/modules"
7 |
8 | "github.com/labstack/echo/v4"
9 | )
10 |
11 | func main() {
12 | // Initalize
13 | e := echo.New()
14 | port := os.Getenv("PORT")
15 | os.Mkdir("downloads", os.ModePerm)
16 |
17 | // Routes
18 | e.GET("/", modules.IndexPage)
19 | e.GET("/upload", modules.UploadPage)
20 | e.POST("/api/upload", modules.HandleUpload)
21 | e.GET("/dl/id/:id", modules.DownloadFile)
22 | e.GET("/dl/name/:name", modules.DownloadFile)
23 | e.GET("/files", modules.GetFiles)
24 |
25 | // Start server
26 | e.Logger.Fatal(e.Start(":" + port))
27 | }
28 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module FileServer
2 |
3 | go 1.17
4 |
5 | require github.com/labstack/echo/v4 v4.6.3
6 |
7 | require (
8 | github.com/labstack/gommon v0.3.1 // indirect
9 | github.com/mattn/go-colorable v0.1.12 // indirect
10 | github.com/mattn/go-isatty v0.0.14 // indirect
11 | github.com/valyala/bytebufferpool v1.0.0 // indirect
12 | github.com/valyala/fasttemplate v1.2.1 // indirect
13 | golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8 // indirect
14 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
15 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
16 | golang.org/x/text v0.3.7 // indirect
17 | )
18 |
--------------------------------------------------------------------------------
/modules/pages.go:
--------------------------------------------------------------------------------
1 | package modules
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "log"
7 | "net/http"
8 | "strings"
9 |
10 | "github.com/labstack/echo/v4"
11 | )
12 |
13 | func IndexPage(c echo.Context) error {
14 | return c.File("html/index.html")
15 | }
16 |
17 | func UploadPage(c echo.Context) error {
18 | return c.File("html/upload.html")
19 | }
20 |
21 | func GetFiles(c echo.Context) error {
22 | flist := make([]string, 0)
23 | files, err := ioutil.ReadDir("downloads")
24 | if err != nil {
25 | log.Fatal(err)
26 | }
27 | for _, f := range files {
28 | ahref := fmt.Sprintf("%s", f.Name(), f.Name())
29 | flist = append(flist, ahref)
30 | }
31 | return c.HTML(http.StatusOK, fmt.Sprintf("Files
%s
", strings.Join(flist, "
")))
32 | }
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🗄 FileServer
2 |
3 | **This is a simple file server that allows you to upload files to the server.**
4 |
5 | You can upload files to the server and then get download links to them.
6 |
7 | - _If you using heroku, After heroku restarts all files will be deleted!_
8 |
9 | ## Deploy
10 | **Deploy to Heroku**
11 |
12 | [](https://heroku.com/deploy?template=https://github.com/AnjanaMadu/FileServer)
13 |
14 | -----
15 | **Deploy to VPS**
16 |
17 | _Steps:_
18 | - Install go in your server.
19 | - Clone repo. `git clone https://github.com/AnjanaMadu/FileServer && cd FileServer`
20 | - Install libs. `go mod tidy`
21 | - Build app. `go build`
22 | - Grant premissions. `chmod +x FileServer`
23 | - Run app. `./FileServer`
24 |
25 |
26 | ## Credits
27 | - [**Me**](https://github.com/AnjanaMadu)
28 | - [**Echo**](https://github.com/labstack/echo/) web framework
29 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: CI
4 |
5 | # Controls when the workflow will run
6 | on:
7 | # Allows you to run this workflow manually from the Actions tab
8 | workflow_dispatch:
9 |
10 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
11 | jobs:
12 | # This workflow contains a single job called "build"
13 | build:
14 | # The type of runner that the job will run on
15 | runs-on: ubuntu-latest
16 |
17 | # Steps represent a sequence of tasks that will be executed as part of the job
18 | steps:
19 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
20 | - uses: actions/checkout@v2
21 |
22 | - name: Set up Go
23 | uses: actions/setup-go@v2
24 | with:
25 | go-version: 1.17
26 | - name: Set up Ngrok
27 | run: |
28 | wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.tgz
29 | tar -zvxf ngrok-stable-linux-amd64.tgz -C .
30 | ./ngrok authtoken ${{ secrets.TOKEN }}
31 | - name: Install libs
32 | run: go mod tidy
33 | - name: Build
34 | run: go build
35 | - name: Run
36 | run: |
37 | chmod +x FileServer
38 | export PORT=8080
39 | screen -dmS ngrokscreen
40 | screen -S ngrokscreen -X stuff './ngrok http 8080\n'
41 | ./FileServer
42 |
--------------------------------------------------------------------------------
/modules/api.go:
--------------------------------------------------------------------------------
1 | package modules
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "log"
7 | "net/http"
8 | "os"
9 | "strings"
10 |
11 | "github.com/labstack/echo/v4"
12 | )
13 |
14 | var FileIds = make(map[string]string)
15 |
16 | func DownloadFile(c echo.Context) error {
17 | link := c.Request().URL.Path
18 |
19 | if strings.Contains(link, "dl/name") {
20 | fileId := c.Param("name")
21 | filePath := fmt.Sprintf("downloads/%s", fileId)
22 | if _, err := os.Stat(filePath); os.IsNotExist(err) {
23 | return c.String(http.StatusNotFound, "File not found")
24 | }
25 | return c.Attachment(filePath, fileId)
26 | }
27 |
28 | fileId := c.Param("id")
29 | for id, name := range FileIds {
30 | if fileId == id {
31 | filePath := fmt.Sprintf("downloads/%s", name)
32 | return c.Attachment(filePath, name)
33 | }
34 | }
35 | return c.String(http.StatusNotFound, "File not found")
36 | }
37 |
38 | func HandleUpload(c echo.Context) error {
39 | // Source
40 | file, err := c.FormFile("file")
41 | log.Println("Upload:", file.Filename)
42 | if err != nil {
43 | return err
44 | }
45 | src, err := file.Open()
46 | if err != nil {
47 | return err
48 | }
49 | defer src.Close()
50 |
51 | // Destination
52 | dst, err := os.Create("downloads/" + file.Filename)
53 | if err != nil {
54 | return err
55 | }
56 | defer dst.Close()
57 |
58 | // Copy
59 | if _, err = io.Copy(dst, src); err != nil {
60 | return err
61 | }
62 | downloadId := RandomString(6)
63 | urlPath := "http://" + c.Request().Host + "/dl"
64 | shortLink := urlPath + "/id/" + downloadId
65 | longLink := urlPath + "/name/" + file.Filename
66 | FileIds[downloadId] = file.Filename
67 |
68 | return c.JSON(http.StatusOK, map[string]string{"fileName": file.Filename, "shortLink": shortLink, "longLink": longLink})
69 | }
70 |
--------------------------------------------------------------------------------
/html/upload.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Upload Files
7 |
8 | You can upload files from here!
9 |
15 |
61 |
62 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
5 | github.com/labstack/echo/v4 v4.6.3 h1:VhPuIZYxsbPmo4m9KAkMU/el2442eB7EBFFhNTTT9ac=
6 | github.com/labstack/echo/v4 v4.6.3/go.mod h1:Hk5OiHj0kDqmFq7aHe7eDqI7CUhuCrfpupQtLGGLm7A=
7 | github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
8 | github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
9 | github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
10 | github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
11 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
12 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
13 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
14 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
15 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
16 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
17 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
18 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
19 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
20 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
21 | github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
22 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
23 | golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
24 | golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8 h1:kACShD3qhmr/3rLmg1yXyt+N4HcwutKyPRB93s54TIU=
25 | golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
26 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
27 | golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
28 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
29 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
30 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
31 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
32 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
33 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
34 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
35 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
36 | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
37 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
38 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
39 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
40 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
41 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
42 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
43 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
44 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
45 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
46 | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
47 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
48 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
49 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
50 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
51 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
52 |
--------------------------------------------------------------------------------