diff --git a/README.md b/README.md
index fa39e75..09dc7a6 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# burgoking
+⚠️ As of September 2022, Burger King migrated their survey system to a third party company, resulting to changes that require an almost complete rebuild of this project. Unfortunately, I cannot find the time nor the will to do it. So, I replaced the generation algorithm with something local and static. In almost all cases, this generator will work (I never encountered a BK employee that checked the numbers). ⚠️
+
🍔 **Burger King - Free Burger Code Generator** 🍔
Generate a Burger King's promotion code to get a free burger using Golang.
@@ -74,9 +76,9 @@ Usage of code:
The [api](https://github.com/Scotow/burgoking/blob/master/cmd/api) command starts a simple web server that returns a new promotion code to each request.
-##### Web friendly server
+##### (Old) Web friendly server
-The [web](https://github.com/Scotow/burgoking/blob/master/cmd/web) command is a ready-for-demo binary that serves a simple, yet beautiful UI generating promotion codes using a pool.
+The [web](https://github.com/Scotow/burgoking/blob/master/cmd/web_original) command is a ready-for-demo binary that serves a simple, yet beautiful UI generating promotion codes using a pool.
The program may setup a second private pool that requires a `Authorization` HTTP header.
diff --git a/cmd/api/main.go b/cmd/api/main.go
index 6af29bc..763c677 100644
--- a/cmd/api/main.go
+++ b/cmd/api/main.go
@@ -14,7 +14,7 @@ const (
)
func handle(w http.ResponseWriter, _ *http.Request) {
- code, err := burgoking.GenerateCode(nil)
+ code, err := burgoking.GenerateCodeStatic(nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
diff --git a/cmd/code/main.go b/cmd/code/main.go
index ed3b989..1de3af1 100644
--- a/cmd/code/main.go
+++ b/cmd/code/main.go
@@ -14,7 +14,7 @@ var (
)
func generateCode() {
- code, err := burgoking.GenerateCode(nil)
+ code, err := burgoking.GenerateCodeStatic(nil)
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
diff --git a/cmd/web/main.go b/cmd/web/main.go
index d1e1aba..430b77f 100644
--- a/cmd/web/main.go
+++ b/cmd/web/main.go
@@ -5,7 +5,6 @@ import (
"log"
"net/http"
"strconv"
- "time"
"github.com/scotow/burgoking"
"github.com/sirupsen/logrus"
@@ -20,59 +19,14 @@ var (
var (
port = flag.Int("p", 8080, "listening port")
contact = flag.String("c", "", "contact address on error")
-
- publicSize = flag.Int("n", 3, "public code pool size")
- publicExpiration = flag.Duration("d", 24*time.Hour, "public code expiration")
- publicRetry = flag.Duration("r", 30*time.Second, "public code regeneration interval")
-
- privateDirectKey = flag.String("k", "", "authorization token for private and direct code (disable if empty)")
- privateSize = flag.Int("N", 1, "private code pool size")
- privateExpiration = flag.Duration("D", 24*time.Hour, "private code expiration")
- privateRetry = flag.Duration("R", 30*time.Second, "private code regeneration interval")
)
-func handleCodeRequest(p *burgoking.Pool, t string, w http.ResponseWriter, r *http.Request) {
- codeC, cancelC := make(chan string), make(chan struct{})
- go p.GetCode(codeC, cancelC)
-
- select {
- case code := <-codeC:
- w.WriteHeader(http.StatusOK)
- w.Header().Set("Content-Type", "text/plain")
- _, _ = w.Write([]byte(code))
- logrus.WithFields(logrus.Fields{"code": code, "ip": realip.FromRequest(r), "type": t}).Info("Code used by user.")
- case <-r.Context().Done():
- cancelC <- struct{}{}
- }
-}
-
-func handlePublic(w http.ResponseWriter, r *http.Request) {
- handleCodeRequest(publicPool, "public", w, r)
-}
-
-func handlePrivate(w http.ResponseWriter, r *http.Request) {
- if r.Header.Get("Authorization") != *privateDirectKey {
- http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
- return
- }
-
- handleCodeRequest(privatePool, "private", w, r)
-}
-
-func handleDirect(w http.ResponseWriter, r *http.Request) {
- if r.Header.Get("Authorization") != *privateDirectKey {
- http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
- return
- }
-
- code, err := burgoking.GenerateCode(nil)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
+func handleCode(w http.ResponseWriter, r *http.Request) {
+ code, _ := burgoking.GenerateCodeStatic(nil)
+ w.WriteHeader(http.StatusOK)
+ w.Header().Set("Content-Type", "text/plain")
_, _ = w.Write([]byte(code))
- logrus.WithFields(logrus.Fields{"code": code, "ip": r.RemoteAddr, "type": "direct"}).Info("Code used by user.")
+ logrus.WithFields(logrus.Fields{"code": code, "ip": realip.FromRequest(r)}).Info("Code used by user.")
}
func handleContact(w http.ResponseWriter, _ *http.Request) {
@@ -84,31 +38,7 @@ func main() {
// Static files.
http.Handle("/", http.FileServer(http.Dir("static")))
-
- // Public pool.
- pool, err := burgoking.NewPool(*publicSize, *publicExpiration, *publicRetry)
- if err != nil {
- logrus.Fatal(err)
- return
- }
- publicPool = pool
-
- http.HandleFunc("/code", handlePublic)
-
- // Private pool.
- if *privateDirectKey != "" {
- pool, err = burgoking.NewPool(*privateSize, *privateExpiration, *privateRetry)
- if err != nil {
- logrus.Fatal(err)
- return
- }
- privatePool = pool
-
- http.HandleFunc("/private", handlePrivate)
- http.HandleFunc("/direct", handleDirect)
-
- logrus.Info("Private and direct code generation activated.")
- }
+ http.HandleFunc("/code", handleCode)
// Contact address.
if *contact != "" {
diff --git a/cmd/web_original/Dockerfile b/cmd/web_original/Dockerfile
new file mode 100644
index 0000000..67a2d88
--- /dev/null
+++ b/cmd/web_original/Dockerfile
@@ -0,0 +1,38 @@
+##################################
+# STEP 1 build executable binary #
+##################################
+FROM golang:alpine AS builder
+
+# Install git.
+# Git is required for fetching the dependencies.
+RUN apk update && apk add --no-cache git
+COPY . $GOPATH/src/github.com/scotow/burgoking
+
+# Move to command directory.
+WORKDIR $GOPATH/src/github.com/scotow/burgoking/cmd/web_original
+
+# Fetch dependencies.
+# Using go get.
+RUN go get -d -v
+
+# Build the binary.
+RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/burgoking
+
+##############################
+# STEP 2 build a small image #
+##############################
+FROM scratch
+
+# Copy our static executable and static files.
+COPY --from=builder /go/bin/burgoking /burgoking
+COPY cmd/web_original/static /static
+
+# Copy SSL certificates for HTTPS connections.
+COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
+
+# Copy locale data.
+COPY --from=builder /usr/local/go/lib/time/zoneinfo.zip /
+ENV ZONEINFO=/zoneinfo.zip
+
+# Run the hello binary.
+ENTRYPOINT ["/burgoking"]
\ No newline at end of file
diff --git a/cmd/web_original/main.go b/cmd/web_original/main.go
new file mode 100644
index 0000000..d1e1aba
--- /dev/null
+++ b/cmd/web_original/main.go
@@ -0,0 +1,119 @@
+package main
+
+import (
+ "flag"
+ "log"
+ "net/http"
+ "strconv"
+ "time"
+
+ "github.com/scotow/burgoking"
+ "github.com/sirupsen/logrus"
+ "github.com/tomasen/realip"
+)
+
+var (
+ publicPool *burgoking.Pool
+ privatePool *burgoking.Pool
+)
+
+var (
+ port = flag.Int("p", 8080, "listening port")
+ contact = flag.String("c", "", "contact address on error")
+
+ publicSize = flag.Int("n", 3, "public code pool size")
+ publicExpiration = flag.Duration("d", 24*time.Hour, "public code expiration")
+ publicRetry = flag.Duration("r", 30*time.Second, "public code regeneration interval")
+
+ privateDirectKey = flag.String("k", "", "authorization token for private and direct code (disable if empty)")
+ privateSize = flag.Int("N", 1, "private code pool size")
+ privateExpiration = flag.Duration("D", 24*time.Hour, "private code expiration")
+ privateRetry = flag.Duration("R", 30*time.Second, "private code regeneration interval")
+)
+
+func handleCodeRequest(p *burgoking.Pool, t string, w http.ResponseWriter, r *http.Request) {
+ codeC, cancelC := make(chan string), make(chan struct{})
+ go p.GetCode(codeC, cancelC)
+
+ select {
+ case code := <-codeC:
+ w.WriteHeader(http.StatusOK)
+ w.Header().Set("Content-Type", "text/plain")
+ _, _ = w.Write([]byte(code))
+ logrus.WithFields(logrus.Fields{"code": code, "ip": realip.FromRequest(r), "type": t}).Info("Code used by user.")
+ case <-r.Context().Done():
+ cancelC <- struct{}{}
+ }
+}
+
+func handlePublic(w http.ResponseWriter, r *http.Request) {
+ handleCodeRequest(publicPool, "public", w, r)
+}
+
+func handlePrivate(w http.ResponseWriter, r *http.Request) {
+ if r.Header.Get("Authorization") != *privateDirectKey {
+ http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
+ return
+ }
+
+ handleCodeRequest(privatePool, "private", w, r)
+}
+
+func handleDirect(w http.ResponseWriter, r *http.Request) {
+ if r.Header.Get("Authorization") != *privateDirectKey {
+ http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
+ return
+ }
+
+ code, err := burgoking.GenerateCode(nil)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ _, _ = w.Write([]byte(code))
+ logrus.WithFields(logrus.Fields{"code": code, "ip": r.RemoteAddr, "type": "direct"}).Info("Code used by user.")
+}
+
+func handleContact(w http.ResponseWriter, _ *http.Request) {
+ _, _ = w.Write([]byte(*contact))
+}
+
+func main() {
+ flag.Parse()
+
+ // Static files.
+ http.Handle("/", http.FileServer(http.Dir("static")))
+
+ // Public pool.
+ pool, err := burgoking.NewPool(*publicSize, *publicExpiration, *publicRetry)
+ if err != nil {
+ logrus.Fatal(err)
+ return
+ }
+ publicPool = pool
+
+ http.HandleFunc("/code", handlePublic)
+
+ // Private pool.
+ if *privateDirectKey != "" {
+ pool, err = burgoking.NewPool(*privateSize, *privateExpiration, *privateRetry)
+ if err != nil {
+ logrus.Fatal(err)
+ return
+ }
+ privatePool = pool
+
+ http.HandleFunc("/private", handlePrivate)
+ http.HandleFunc("/direct", handleDirect)
+
+ logrus.Info("Private and direct code generation activated.")
+ }
+
+ // Contact address.
+ if *contact != "" {
+ http.HandleFunc("/contact", handleContact)
+ }
+
+ log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), nil))
+}
diff --git a/cmd/web_original/static/browserconfig.xml b/cmd/web_original/static/browserconfig.xml
new file mode 100644
index 0000000..6a1d00e
--- /dev/null
+++ b/cmd/web_original/static/browserconfig.xml
@@ -0,0 +1,9 @@
+
+