Files
gaslight/internal/rewrite/html.go
2026-04-23 20:36:37 +03:00

125 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package rewrite
import (
"bytes"
"compress/flate"
"compress/gzip"
"fmt"
"io"
"log"
"net/http"
"regexp"
"strings"
"git.gulenok.ru/greenhaze/gaslight/internal/cheating"
"git.gulenok.ru/greenhaze/gaslight/internal/latex"
"git.gulenok.ru/greenhaze/gaslight/internal/openrouter"
)
var questionTestDivRe = regexp.MustCompile(`(?is)<div[^>]*\bid\s*=\s*["'][^"']*\bQuestionTest\b[^"']*["'][^>]*>`)
type HTMLHook func(req *http.Request, html []byte) ([]byte, error)
type Processor struct {
hook HTMLHook
}
func NewProcessor(hook HTMLHook) *Processor {
return &Processor{hook: hook}
}
func DefaultQuestionTestHook(_ *http.Request, html []byte) ([]byte, error) {
switch cheating.DetermineQuestionType(string(html)) {
case cheating.FullTextQuestion:
{
aiResponce, err := openrouter.AskOpenRouter(fmt.Sprintf("РЕШИ ЗАДАНИЕ И ДАЙ МАКСИМАЛЬНО КРАТКИЙ ОТВЕТ: %s", string(html)))
if err != nil {
log.Printf("openrouter failed %s", err)
return html, nil
}
return []byte(strings.ReplaceAll(string(html), "generated", latex.ConvertLaTeXToASCII(aiResponce))), nil
}
case cheating.QuestionWithPicture:
{
}
}
return []byte(strings.ReplaceAll(string(html), "generated", "pwned")), nil
}
func IsHTMLResponse(contentType string) bool {
contentType = strings.ToLower(contentType)
return strings.Contains(contentType, "text/html") || strings.Contains(contentType, "application/xhtml+xml")
}
func (p *Processor) RewriteIfNeeded(req *http.Request, contentEncoding string, body []byte) ([]byte, error) {
decoded, err := decodeBody(contentEncoding, body)
if err != nil {
return nil, err
}
if !questionTestDivRe.Match(decoded) {
return body, nil
}
modifiedDecoded, err := p.hook(req, decoded)
if err != nil {
return nil, err
}
return encodeBody(contentEncoding, modifiedDecoded)
}
func decodeBody(encoding string, body []byte) ([]byte, error) {
switch strings.ToLower(strings.TrimSpace(encoding)) {
case "", "identity":
return body, nil
case "gzip":
r, err := gzip.NewReader(bytes.NewReader(body))
if err != nil {
return nil, err
}
defer r.Close()
return io.ReadAll(r)
case "deflate":
r := flate.NewReader(bytes.NewReader(body))
defer r.Close()
return io.ReadAll(r)
default:
return nil, fmt.Errorf("unsupported content-encoding: %s", encoding)
}
}
func encodeBody(encoding string, decoded []byte) ([]byte, error) {
switch strings.ToLower(strings.TrimSpace(encoding)) {
case "", "identity":
return decoded, nil
case "gzip":
var buf bytes.Buffer
w := gzip.NewWriter(&buf)
if _, err := w.Write(decoded); err != nil {
_ = w.Close()
return nil, err
}
if err := w.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
case "deflate":
var buf bytes.Buffer
w, err := flate.NewWriter(&buf, flate.DefaultCompression)
if err != nil {
return nil, err
}
if _, err := w.Write(decoded); err != nil {
_ = w.Close()
return nil, err
}
if err := w.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
default:
return nil, fmt.Errorf("unsupported content-encoding: %s", encoding)
}
}