Skip to content

Commit

Permalink
Move to static generator
Browse files Browse the repository at this point in the history
  • Loading branch information
scotow authored and BENJAMIN LOPEZ committed Sep 1, 2022
1 parent e953e9b commit fba3698
Show file tree
Hide file tree
Showing 21 changed files with 332 additions and 80 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cmd/code/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
82 changes: 6 additions & 76 deletions cmd/web/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"log"
"net/http"
"strconv"
"time"

"github.com/scotow/burgoking"
"github.com/sirupsen/logrus"
Expand All @@ -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) {
Expand All @@ -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 != "" {
Expand Down
38 changes: 38 additions & 0 deletions cmd/web_original/Dockerfile
Original file line number Diff line number Diff line change
@@ -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"]
119 changes: 119 additions & 0 deletions cmd/web_original/main.go
Original file line number Diff line number Diff line change
@@ -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))
}
9 changes: 9 additions & 0 deletions cmd/web_original/static/browserconfig.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/icons/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>
52 changes: 52 additions & 0 deletions cmd/web_original/static/css/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@import url(https://fonts.googleapis.com/css?family=Lobster);

html, body {
height: 100%;
}

html {
font-size: 0;
font-family: 'Lobster', sans-serif;
color: #fff;
background: #131313;
}

body {
margin: 0;
padding: 0;

display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

body::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: #15b154;
}

.video {
flex: 0;
width: 80vw;
max-width: 300px;
border-radius: 35%;
}

.label {
margin-top: 20px;
text-align: center;
color: white;
font-size: 36px;
font-family: 'Lobster', sans-serif;
}

.label.done {
margin-top: 18px;
font-size: 44px;
}
Binary file added cmd/web_original/static/favicon.ico
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added cmd/web_original/static/icons/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added cmd/web_original/static/icons/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added cmd/web_original/static/icons/mstile-150x150.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions cmd/web_original/static/icons/safari-pinned-tab.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit fba3698

Please sign in to comment.