Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
unixpickle
GitHub Repository: unixpickle/kahoot-hack
Path: blob/master/kahoot-profane/main.go
10110 views
1
package main
2
3
import (
4
"fmt"
5
"io/ioutil"
6
"net/http"
7
"net/url"
8
"os"
9
"os/signal"
10
"strconv"
11
"sync"
12
"syscall"
13
14
"github.com/unixpickle/kahoot-hack/kahoot"
15
)
16
17
const ConcurrencyCount = 4
18
19
func main() {
20
if len(os.Args) != 4 {
21
fmt.Fprintln(os.Stderr, "Usage: profane <game pin> <nickname prefix> <count>")
22
os.Exit(1)
23
}
24
25
gamePin := os.Args[1]
26
27
var dieLock sync.Mutex
28
connChan := make(chan *kahoot.Conn)
29
for i := 0; i < ConcurrencyCount; i++ {
30
go func() {
31
for {
32
conn, err := kahoot.NewConn(gamePin)
33
if err != nil {
34
dieLock.Lock()
35
fmt.Fprintln(os.Stderr, "failed to connect:", err)
36
os.Exit(1)
37
dieLock.Unlock()
38
}
39
connChan <- conn
40
}
41
}()
42
}
43
44
for _, nickname := range nicknames() {
45
conn := <-connChan
46
defer conn.GracefulClose()
47
conn.Login(nickname)
48
}
49
50
fmt.Println("Kill this process to deauthenticate.")
51
sigChan := make(chan os.Signal, 1)
52
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
53
<-sigChan
54
}
55
56
func nicknames() []string {
57
count, err := strconv.Atoi(os.Args[3])
58
if err != nil {
59
fmt.Fprintln(os.Stderr, "invalid count:", os.Args[3])
60
os.Exit(1)
61
}
62
base, err := sanitizeName(os.Args[2])
63
if err != nil {
64
fmt.Fprintln(os.Stderr, "Failed to sanitize nickname:", err)
65
os.Exit(1)
66
}
67
res := make([]string, count)
68
for x := 0; x < count; x++ {
69
res[x] = base + strconv.Itoa(x+1)
70
}
71
return res
72
}
73
74
func sanitizeName(name string) (string, error) {
75
for interval := 16; interval > 1; interval-- {
76
attempt := boldify(name, interval)
77
testURL := "https://play.kahoot.it/profanity/profanities/nickname/" +
78
url.QueryEscape(attempt)
79
resp, err := http.Get(testURL)
80
if resp != nil {
81
defer resp.Body.Close()
82
}
83
if err != nil {
84
return "", err
85
}
86
contents, err := ioutil.ReadAll(resp.Body)
87
if err != nil {
88
return "", err
89
}
90
if string(contents) == "[]" {
91
return attempt, nil
92
}
93
}
94
return boldify(name, 1), nil
95
}
96
97
func boldify(name string, interval int) string {
98
var res []rune
99
for i, x := range name {
100
if i%interval != 0 {
101
res = append(res, x)
102
continue
103
}
104
switch true {
105
case x >= 'a' && x <= 'z':
106
res = append(res, 120302+x-'a')
107
case x >= 'A' && x <= 'Z':
108
res = append(res, 120276+x-'A')
109
default:
110
res = append(res, x)
111
}
112
}
113
return string(res)
114
}
115
116