Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
unixpickle
GitHub Repository: unixpickle/kahoot-hack
Path: blob/master/kahoot/quiz.go
10110 views
1
package kahoot
2
3
import (
4
"encoding/json"
5
"errors"
6
"strconv"
7
)
8
9
type QuizActionType int
10
11
const (
12
QuestionIntro QuizActionType = iota
13
QuestionAnswers
14
)
15
16
type QuizAction struct {
17
Type QuizActionType
18
NumAnswers int
19
Index int
20
AnswerMap map[int]int
21
}
22
23
type Quiz struct {
24
conn *Conn
25
}
26
27
func NewQuiz(c *Conn) *Quiz {
28
return &Quiz{c}
29
}
30
31
// Receive receives the next QuizAction.
32
// This may be a QuestionIntro, indicating a new question is starting,
33
// or QuestionAnswers, indicating that the user may now submit an answer.
34
func (q *Quiz) Receive() (*QuizAction, error) {
35
PacketLoop:
36
for {
37
packet, err := q.conn.Receive("/service/player")
38
if err != nil {
39
return nil, err
40
}
41
var content Message
42
if data, ok := packet["data"].(map[string]interface{}); !ok {
43
continue
44
} else if id, ok := data["id"].(float64); !ok {
45
continue
46
} else if contentStr, ok := data["content"].(string); !ok {
47
continue
48
} else if json.Unmarshal([]byte(contentStr), &content) != nil {
49
continue
50
} else if numArray, ok := content["quizQuestionAnswers"].([]interface{}); !ok {
51
continue
52
} else if questionIndex, ok := content["questionIndex"].(float64); !ok {
53
continue
54
} else if int(questionIndex) >= len(numArray) || int(questionIndex) < 0 {
55
continue
56
} else if numAnswers, ok := numArray[int(questionIndex)].(float64); !ok {
57
continue
58
} else if answerMap, ok := content["answerMap"].(map[string]interface{}); !ok {
59
continue
60
} else {
61
var t QuizActionType
62
if id == 1 {
63
t = QuestionIntro
64
} else if id == 2 {
65
t = QuestionAnswers
66
} else {
67
continue
68
}
69
70
intAnswerMap := map[int]int{}
71
for key, val := range answerMap {
72
intKey, err := strconv.Atoi(key)
73
if err != nil {
74
continue PacketLoop
75
}
76
if num, ok := val.(float64); !ok {
77
continue PacketLoop
78
} else {
79
intAnswerMap[intKey] = int(num)
80
}
81
}
82
83
return &QuizAction{
84
Type: t,
85
NumAnswers: int(numAnswers),
86
Index: int(questionIndex),
87
AnswerMap: intAnswerMap,
88
}, nil
89
}
90
}
91
}
92
93
// Send responds to a server's QuestionAnswers action with an answer index.
94
func (q *Quiz) Send(index int) error {
95
content := Message{
96
"choice": index,
97
"meta": Message{
98
"lag": 22,
99
"device": Message{
100
"userAgent": "hack",
101
"screen": Message{
102
"width": 1337,
103
"height": 1337,
104
},
105
},
106
},
107
}
108
encodedContent, _ := json.Marshal(content)
109
message := Message{
110
"data": Message{
111
"id": 45,
112
"type": "message",
113
"gameid": q.conn.gameId,
114
"host": "kahoot.it",
115
"content": string(encodedContent),
116
},
117
}
118
if err := q.conn.Send("/service/controller", message); err != nil {
119
return err
120
}
121
if controllerMsg, err := q.conn.Receive("/service/controller"); err != nil {
122
return err
123
} else if success, ok := controllerMsg["successful"].(bool); !ok || !success {
124
return errors.New("did not receive successful response")
125
}
126
return nil
127
}
128
129