Browse Source

First commit

master
Alfred 5 months ago
commit
fd8c8b5aab
5 changed files with 180 additions and 0 deletions
  1. 11
    0
      Dockerfile
  2. 23
    0
      README.md
  3. 8
    0
      go.mod
  4. 31
    0
      go.sum
  5. 107
    0
      shortener.go

+ 11
- 0
Dockerfile View File

@@ -0,0 +1,11 @@
1
+FROM golang:1.13-alpine
2
+
3
+RUN apk add --update gcc musl-dev
4
+
5
+RUN mkdir -p /srv/data; mkdir -p /srv/code;
6
+COPY . /srv/code
7
+
8
+WORKDIR /srv/code
9
+RUN go build -ldflags="-w -s" -o /srv/shortener
10
+
11
+CMD "/srv/shortener"

+ 23
- 0
README.md View File

@@ -0,0 +1,23 @@
1
+# The castizo shortener
2
+
3
+The castizo shortener is a url shortener hosted in [eñ.xyz](https://eñ.xyz). However, you can host it wherever you want because you have the source code just here.
4
+
5
+You can run once you have created the path `/srv/data`. There the shortener will put its database. To run it, with a Go cli:
6
+
7
+```
8
+go run shortener.go
9
+```
10
+
11
+Also you can use Docker to build it:
12
+
13
+```
14
+docker build -t shortener .
15
+```
16
+
17
+And to run it:
18
+
19
+```
20
+docker run -p 6660:6660 shortener
21
+```
22
+
23
+It was done in 30 mins, so do not judge its results...

+ 8
- 0
go.mod View File

@@ -0,0 +1,8 @@
1
+module the-castizo-shortener
2
+
3
+go 1.12
4
+
5
+require (
6
+	github.com/gin-gonic/gin v1.4.0
7
+	github.com/mattn/go-sqlite3 v1.11.0
8
+)

+ 31
- 0
go.sum View File

@@ -0,0 +1,31 @@
1
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2
+github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
3
+github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
4
+github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
5
+github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
6
+github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
7
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
8
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
9
+github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
10
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
11
+github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
12
+github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
13
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
14
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
18
+github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
19
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
20
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
21
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
22
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
23
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
24
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
25
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
26
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
27
+gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
28
+gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
29
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
30
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
31
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 107
- 0
shortener.go View File

@@ -0,0 +1,107 @@
1
+package main
2
+
3
+import "github.com/gin-gonic/gin"
4
+import "database/sql"
5
+import "net/http"
6
+import "strings"
7
+import "math/rand"
8
+import "time"
9
+import (
10
+	_ "github.com/mattn/go-sqlite3"
11
+)
12
+
13
+func main() {
14
+	rand.Seed(time.Now().UnixNano())
15
+	db, err := sql.Open("sqlite3", "/srv/data/database.db")
16
+	if err != nil {
17
+		panic(err)
18
+	}
19
+	statement, err := db.Prepare("CREATE TABLE IF NOT EXISTS urls (identifier CHAR(50) PRIMARY KEY, url TEXT)")
20
+	if err != nil {
21
+		panic(err)
22
+	}
23
+
24
+	_, err = statement.Exec()
25
+	if err != nil {
26
+		panic(err)
27
+	}
28
+
29
+	engine := gin.Default()
30
+	engine.GET("", func(context *gin.Context) {
31
+		context.Data(http.StatusOK, "text/html; charset=utf-8", []byte(`
32
+<!DOCTYPE html>
33
+<html>
34
+  <head>
35
+  <meta charset="UTF-8"><title>The Castizo Shortener</title><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
36
+  </head>
37
+  <body>
38
+  		<form method="post" id="_form"><div class="container valign-wrapper" style="height: 100vh;">
39
+		<input type="text" placeholder="Let me know the url to shorten (press ENTER to finish)" id="_url" name="_url" onkeydown="javascript:if(event.which == 13)document.getElementById('_form').submit();" />
40
+		</div></form>
41
+  </body>
42
+</html>
43
+		`))
44
+	})
45
+	engine.POST("", func(context *gin.Context) {
46
+		max := func(v1 int, v2 int) int {
47
+			if (v1 > v2) {
48
+				return v1
49
+			}
50
+			return v2
51
+		}
52
+
53
+		get_identifier := func (n int) string {
54
+			possible := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
55
+			b := make([]byte, n)
56
+			for i := range b {
57
+				b[i] = possible[rand.Intn(len(possible))]
58
+			}
59
+			return string(b)
60
+		}
61
+
62
+		context.Request.ParseForm()
63
+		url := context.Request.PostForm["_url"][0]
64
+
65
+		idx1 := strings.Index(url, "--")
66
+		idx2 := strings.Index(url, "\\*")
67
+		idx3 := strings.Index(url, "*/")
68
+		idx := max(idx1, max(idx2, idx3))
69
+		if len(url) < len("http://a.es") || !(url[:7] == "http://" || url[:8] == "https://") || idx > -1 {
70
+			context.Redirect(http.StatusFound, "")
71
+			return;
72
+		}
73
+
74
+		identifier := ""
75
+		trial := 1
76
+		letters := trial
77
+		insert, _ := db.Prepare("INSERT INTO urls(identifier, url) values(?,?)")
78
+		for identifier == "" {
79
+			rows, _ := db.Query("SELECT identifier FROM urls WHERE url=$1", url)
80
+			rows.Next()
81
+			rows.Scan(&identifier)
82
+			if identifier == "" {
83
+				rvalue := get_identifier(letters)
84
+				insert.Exec(rvalue, url)
85
+			}
86
+			rows.Close()
87
+			trial = trial + 1
88
+			if (trial % 5) == 0 {
89
+				letters = letters + 1
90
+			}
91
+		}
92
+		context.Data(http.StatusOK, "application/json", []byte("{\"url\": \"" + context.Request.Header.Get("Referer") + identifier + "\"}"))
93
+	})
94
+	engine.GET("/:identifier", func(context *gin.Context) {
95
+		identifier := context.Param("identifier")
96
+		var url string
97
+		rows, _ := db.Query("SELECT url FROM urls WHERE identifier=$1", identifier)
98
+		rows.Next()
99
+		rows.Scan(&url)
100
+		rows.Close()
101
+		context.Redirect(http.StatusMovedPermanently, url)
102
+	})
103
+	err = engine.Run(":6660")
104
+	if err != nil {
105
+		panic(err)
106
+	}
107
+}

Loading…
Cancel
Save