commit 6b6b7201c3b6725cffc0dbc13a85f6899bc56397
parent 79629fa300022a89071c99e7bebf2e926827dc76
Author: n0tr1v <n0tr1v@protonmail.com>
Date: Sun, 11 Jun 2023 13:49:35 -0700
insanity v2
Diffstat:
4 files changed, 257 insertions(+), 27 deletions(-)
diff --git a/pkg/web/handlers/handlers.go b/pkg/web/handlers/handlers.go
@@ -4907,6 +4907,181 @@ func chessGamePromoB(g *interceptors.ChessGame) {
g.MoveStr("axb7")
}
+func chessGameKingSideCastle(g *interceptors.ChessGame) {
+ g.MoveStr("e3")
+ g.MoveStr("e6")
+ g.MoveStr("Be2")
+ g.MoveStr("Be7")
+ g.MoveStr("Nf3")
+ g.MoveStr("Nf6")
+}
+
+func chessGameQueenSideCastle(g *interceptors.ChessGame) {
+ g.MoveStr("d4")
+ g.MoveStr("d5")
+ g.MoveStr("Qd3")
+ g.MoveStr("Qd6")
+ g.MoveStr("Bd2")
+ g.MoveStr("Bd7")
+ g.MoveStr("Nc3")
+ g.MoveStr("Nc6")
+}
+
+func ChessGameFormHandler(c echo.Context) error {
+ key := c.Param("key")
+ out := `<style>
+/* http://meyerweb.com/eric/tools/css/reset/
+ v2.0 | 20110126
+ License: none (public domain)
+*/
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+body {
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+/* --- end --- */
+.newBoard {
+ position: relative;
+ aspect-ratio: 1 / 1;
+ width: 100%;
+ min-height: 360px;
+}
+.newBoard .img {
+ position: absolute;
+ width: 12.5%;
+ height: 12.5%;
+ background-size: 100%;
+}
+.idk {
+ width: 100%;
+ height: 100%;
+}
+label {
+ position: absolute;
+ width: 12.5%;
+ height: 12.5%;
+}
+input[type=checkbox] {
+ display:none;
+}
+input[type=checkbox] + label {
+ display: inline-block;
+ padding: 0 0 0 0;
+ margin: 0 0 0 0;
+ background-size: 100%;
+ border: 3px solid transparent;
+ box-sizing: border-box;
+}
+input[type=checkbox]:checked + label {
+ display: inline-block;
+ background-size: 100%;
+ border: 3px solid red;
+}
+</style>`
+
+ authUser := c.Get("authUser").(*database.User)
+ g := interceptors.ChessInstance.GetGame(key)
+ isFlipped := authUser.ID == g.Player2.ID
+
+ out += `<form method="post" action="/chess/` + key + `">
+<table class="newBoard">`
+ for i := 0; i < 64; i++ {
+ id := i
+ mm := 0
+ switch i % 8 {
+ case 0:
+ mm = -7
+ case 1:
+ mm = -5
+ case 2:
+ mm = -3
+ case 3:
+ mm = -1
+ case 4:
+ mm = 1
+ case 5:
+ mm = 3
+ case 6:
+ mm = 5
+ case 7:
+ mm = 7
+ }
+ if !isFlipped {
+ id = (63 - i) + mm
+ } else {
+ id = i - mm
+ }
+ if i%8 == 0 {
+ if i != 0 {
+ out += "</tr>"
+ }
+ out += "<tr>"
+ }
+ idStr := strconv.Itoa(id)
+ out += `<td><div class="idk">`
+ out += `<input name="sq_` + idStr + `" id="sq_` + idStr + `" type="checkbox" value="1" /><label for="sq_` + idStr + `"></label>`
+ out += "</div></td>"
+ }
+ csrf, _ := c.Get("csrf").(string)
+ out += `</tr></table>
+ <input type="hidden" name="csrf" value="` + csrf + `" />
+ <input type="hidden" name="message" value="/pm {{ .Username }} /c move" />
+ <div style="width: 100%; display: flex; margin: 5px 0;">
+ <div>
+ <button type="submit" style="background-color: #aaa;">Move</button>
+ </div>
+ <div style="margin-left: auto;">
+ <span style="color: #aaa; margin-left: 20px;">Promo:</span>
+ <select name="promotion" style="background-color: #aaa;">
+ <option value="queen">Queen</option>
+ <option value="rook">Rook</option>
+ <option value="knight">Knight</option>
+ <option value="bishop">Bishop</option>
+ </select>
+ </div>
+ </div>
+</form>`
+ return c.HTML(http.StatusOK, out)
+}
+
func ChessGameHandler(c echo.Context) error {
authUser := c.Get("authUser").(*database.User)
db := c.Get("database").(*database.DkfDB)
@@ -4919,7 +5094,7 @@ func ChessGameHandler(c echo.Context) error {
user2, _ := db.GetUserByID(30814)
interceptors.ChessInstance.NewGame(key, user1, user2)
g = interceptors.ChessInstance.GetGame(key)
- chessGamePromoB(g)
+ chessGameQueenSideCastle(g)
//return c.Redirect(http.StatusFound, "/")
}
@@ -4944,18 +5119,18 @@ func ChessGameHandler(c echo.Context) error {
isFlipped = true
}
- isYourTurnFn := func() bool {
- return authUser.ID == g.Player1.ID && g.Game.Position().Turn() == chess.White ||
- authUser.ID == g.Player2.ID && g.Game.Position().Turn() == chess.Black
- }
- isYourTurn := isYourTurnFn()
+ //isYourTurnFn := func() bool {
+ // return authUser.ID == g.Player1.ID && g.Game.Position().Turn() == chess.White ||
+ // authUser.ID == g.Player2.ID && g.Game.Position().Turn() == chess.Black
+ //}
+ //isYourTurn := isYourTurnFn()
// If you are not a spectator, and it's your turn to play, we just render the form directly.
- if isYourTurn || g.Game.Outcome() != chess.NoOutcome {
+ if g.Game.Outcome() != chess.NoOutcome {
c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
c.Response().WriteHeader(http.StatusOK)
_, _ = c.Response().Write([]byte(cssReset))
- card1 := g.DrawPlayerCard(isFlipped, isYourTurn)
+ card1 := g.DrawPlayerCard(key, isFlipped, false)
_, _ = c.Response().Write([]byte(fmt.Sprintf(`<div id="div_0">%s</div>`, card1)))
return nil
}
@@ -4984,7 +5159,7 @@ func ChessGameHandler(c echo.Context) error {
if isSpectator {
card1 = g.DrawSpectatorCard(isFlipped)
} else {
- card1 = g.DrawPlayerCard(isFlipped, isYourTurn)
+ card1 = g.DrawPlayerCard(key, isFlipped, false)
}
_, _ = c.Response().Write([]byte(fmt.Sprintf(`<div id="div_0">%s</div>`, card1)))
@@ -5055,6 +5230,44 @@ Loop:
}(payload, c)
}
+ if payload.Turn == chess.White && payload.Move.HasTag(chess.KingSideCastle) {
+ x := int(chess.F1.File())
+ y := int(chess.F1.Rank())
+ if isFlipped {
+ x = 7 - x
+ } else {
+ y = 7 - y
+ }
+ _, _ = c.Response().Write([]byte(fmt.Sprintf(`<style>#img_7 { left: calc(%d*12.5%%) !important; top: calc(%d*12.5%%) !important; }</style>`, x, y)))
+ } else if payload.Turn == chess.Black && payload.Move.HasTag(chess.KingSideCastle) {
+ x := int(chess.F8.File())
+ y := int(chess.F8.Rank())
+ if isFlipped {
+ x = 7 - x
+ } else {
+ y = 7 - y
+ }
+ _, _ = c.Response().Write([]byte(fmt.Sprintf(`<style>#img_63 { left: calc(%d*12.5%%) !important; top: calc(%d*12.5%%) !important; }</style>`, x, y)))
+ } else if payload.Turn == chess.White && payload.Move.HasTag(chess.QueenSideCastle) {
+ x := int(chess.D1.File())
+ y := int(chess.D1.Rank())
+ if isFlipped {
+ x = 7 - x
+ } else {
+ y = 7 - y
+ }
+ _, _ = c.Response().Write([]byte(fmt.Sprintf(`<style>#img_0 { left: calc(%d*12.5%%) !important; top: calc(%d*12.5%%) !important; }</style>`, x, y)))
+ } else if payload.Turn == chess.Black && payload.Move.HasTag(chess.QueenSideCastle) {
+ x := int(chess.D8.File())
+ y := int(chess.D8.Rank())
+ if isFlipped {
+ x = 7 - x
+ } else {
+ y = 7 - y
+ }
+ _, _ = c.Response().Write([]byte(fmt.Sprintf(`<style>#img_56 { left: calc(%d*12.5%%) !important; top: calc(%d*12.5%%) !important; }</style>`, x, y)))
+ }
+
_, _ = c.Response().Write([]byte(`<style>.square { background-color: transparent !important; }</style>`))
_, _ = c.Response().Write([]byte(`<style>.square_` + strconv.Itoa(int(payload.Move.S1())) + `, .square_` + strconv.Itoa(int(payload.Move.S2())) + ` { background-color: rgba(0, 255, 0, 0.2) !important; }</style>`))
diff --git a/pkg/web/handlers/interceptors/chess.go b/pkg/web/handlers/interceptors/chess.go
@@ -383,11 +383,11 @@ func (g *ChessGame) renderBoardB64(isFlipped bool) string {
return imgB64
}
-func (g *ChessGame) DrawPlayerCard(isBlack, isYourTurn bool) string {
- return g.drawPlayerCard("", isBlack, isYourTurn)
+func (g *ChessGame) DrawPlayerCard(key string, isBlack, isYourTurn bool) string {
+ return g.drawPlayerCard(key, "", isBlack, isYourTurn)
}
-func (g *ChessGame) drawPlayerCard(roomName string, isBlack, isYourTurn bool) string {
+func (g *ChessGame) drawPlayerCard(key, roomName string, isBlack, isYourTurn bool) string {
enemy := utils.Ternary(isBlack, g.Player1, g.Player2)
imgB64 := g.renderBoardB64(isBlack)
@@ -419,7 +419,8 @@ func (g *ChessGame) drawPlayerCard(roomName string, isBlack, isYourTurn bool) st
<input type="hidden" name="message" value="resign" />
<button type="submit" style="background-color: #aaa; margin: 5px 0;">Resign</button>
</form>
- <div>
+ <div style="position: relative;">
+ <iframe src="/chess/{{ .Key }}/form" style="position: absolute; top: 0; left: 0; border: 0px solid red; z-index: 999; width: 100%; height: 100%;"></iframe>
<form method="post"{{ if .InChat }} action="/api/v1/chess"{{ end }} style="aspect-ratio: 1/1; height: 70%;">
{{ .Table }}
{{ if .InChat }}
@@ -466,17 +467,17 @@ func (g *ChessGame) drawPlayerCard(roomName string, isBlack, isYourTurn bool) st
`
data := map[string]any{
- "RoomName": roomName,
- "IsYourTurn": isYourTurn,
- "InChat": roomName != "",
- "White": g.Player1,
- "Black": g.Player2,
- "Username": enemy.Username,
- "Table": template.HTML(g.renderBoardHTML(isBlack, imgB64, false)),
- "ImgB64": imgB64,
- "Outcome": g.Game.Outcome().String(),
- "GameOver": g.Game.Outcome() != chess.NoOutcome,
- "PGN": g.Game.String(),
+ "Key": key,
+ "RoomName": roomName,
+ "InChat": roomName != "",
+ "White": g.Player1,
+ "Black": g.Player2,
+ "Username": enemy.Username,
+ "Table": template.HTML(g.renderBoardHTML(isBlack, imgB64, false)),
+ "ImgB64": imgB64,
+ "Outcome": g.Game.Outcome().String(),
+ "GameOver": g.Game.Outcome() != chess.NoOutcome,
+ "PGN": g.Game.String(),
}
fns := template.FuncMap{
@@ -672,6 +673,19 @@ func (b *Chess) SendMove(gameKey string, userID database.UserID, g *ChessGame, c
delete(g.PiecesCache, mov.S1())
delete(g.PiecesCache, mov.S2())
g.PiecesCache[mov.S2()] = idStr1
+ if turn == chess.White && mov.HasTag(chess.KingSideCastle) {
+ delete(g.PiecesCache, chess.H1)
+ g.PiecesCache[chess.F1] = "img_7"
+ } else if turn == chess.Black && mov.HasTag(chess.KingSideCastle) {
+ delete(g.PiecesCache, chess.H8)
+ g.PiecesCache[chess.F8] = "img_63"
+ } else if turn == chess.White && mov.HasTag(chess.QueenSideCastle) {
+ delete(g.PiecesCache, chess.A1)
+ g.PiecesCache[chess.D1] = "img_0"
+ } else if turn == chess.Black && mov.HasTag(chess.QueenSideCastle) {
+ delete(g.PiecesCache, chess.A8)
+ g.PiecesCache[chess.D8] = "img_56"
+ }
ChessPubSub.Pub(gameKey, chessMov)
// Notify (pm) the opponent that you made a move
@@ -766,10 +780,10 @@ func (b *Chess) PlayMove(enemyUsername database.Username, pos string, authUser d
logrus.Error(err)
}
- card1 := g.drawPlayerCard(roomName, false, true)
+ card1 := g.drawPlayerCard(gameKey, roomName, false, true)
_, _ = b.db.CreateMsg(card1, card1, roomKey, roomID, b.zeroID, &g.Player1.ID)
- card1 = g.drawPlayerCard(roomName, true, true)
+ card1 = g.drawPlayerCard(gameKey, roomName, true, true)
_, _ = b.db.CreateMsg(card1, card1, roomKey, roomID, b.zeroID, &g.Player2.ID)
return nil
diff --git a/pkg/web/middlewares/middlewares.go b/pkg/web/middlewares/middlewares.go
@@ -273,7 +273,8 @@ func IsAuthMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
db.DB().Model(user).Update("last_seen_at", time.Now())
// Prevent clickjacking by setting the header on every logged in page
- if !strings.Contains(c.Path(), "/api/v1/chat/messages") &&
+ if !strings.Contains(c.Path(), "/chess/:key/form") &&
+ !strings.Contains(c.Path(), "/api/v1/chat/messages") &&
!strings.Contains(c.Path(), "/api/v1/chat/messages/:roomName/stream") &&
!strings.Contains(c.Path(), "/api/v1/chat/top-bar") &&
!strings.Contains(c.Path(), "/api/v1/chat/controls") {
diff --git a/pkg/web/web.go b/pkg/web/web.go
@@ -102,6 +102,8 @@ func getMainServer(db *database.DkfDB, i18nBundle *i18n.Bundle, renderer *tmp.Te
authGroup.POST("/chess", handlers.ChessHandler)
authGroup.GET("/chess/:key", handlers.ChessGameHandler)
authGroup.POST("/chess/:key", handlers.ChessGameHandler)
+ authGroup.GET("/chess/:key/form", handlers.ChessGameFormHandler)
+ authGroup.POST("/chess/:key/form", handlers.ChessGameFormHandler)
authGroup.GET("/settings/chat", handlers.SettingsChatHandler)
authGroup.POST("/settings/chat", handlers.SettingsChatHandler, middlewares.AuthRateLimitMiddleware(2*time.Second, 1))
authGroup.GET("/settings/chat/pm", handlers.SettingsChatPMHandler)