kaptchapelo/kaptchapelo.lisp

95 lines
3.5 KiB
Common Lisp
Raw Normal View History

2023-08-06 00:07:04 -05:00
;;; Copyright 2023, Jaidyn Ann <jadedctrl@posteo.at>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU General Public License as
;;; published by the Free Software Foundation, either version 3 of
;;; the License, or (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(defpackage #:kaptchapelo
(:use #:cl)
(:export :start-server))
(in-package #:kaptchapelo)
(defun byte-array-to-hex-string (simple-array)
"Given an array of bytes (integers), return an equivalent string in hex."
(string-downcase
(reduce #'str:concat
(loop for byte across simple-array
collect (format nil "~2,'0X" byte)))))
(defun random-file (directory &key (file-ext ""))
(alexandria:random-elt
(directory (str:concat (format nil "~A" directory)
"/*"
(if (not (str:emptyp file-ext))
(str:concat "." file-ext)
"")))))
(defun new-captcha-json (captcha-image-uri captcha-text-file)
2023-08-06 00:07:04 -05:00
"Return the kocaptcha-formed JSON to be returned for a new captcha request."
(yason:with-output-to-string* ()
(yason:encode-plist
(list "md5" (byte-array-to-hex-string captcha-text-file)
"url" captcha-image-uri
"token" "This_isnt_actually_used_lol"))))
2023-08-06 00:07:04 -05:00
(defun new-captcha-response (captcha-dir)
2023-08-06 00:07:04 -05:00
"Create an HTTP response for use with Clack with a new captcha."
(let* ((captcha-txt-file (random-file captcha-dir :file-ext "txt"))
(captcha-img-file (str:concat (pathname-name captcha-txt-file) ".png"))
(captcha-md5-str (byte-array-to-hex-string
(md5:md5sum-file captcha-txt-file))))
(list 201 '(:content-type "application/json")
(list (new-captcha-json (str:concat "/captcha/" captcha-img-file)
captcha-md5-str)))))
2023-08-06 00:07:04 -05:00
2023-08-08 14:34:49 -05:00
(defun image-response (request-uri captcha-dir)
(let ((image-path (str:replace-first "/captcha/" (format nil "~A" captcha-dir) request-uri)))
(list 201 '(:content-type "image/png") (pathname image-path))))
2023-08-06 00:07:04 -05:00
2023-08-08 14:34:49 -05:00
(defun index-response ()
'(201 (:content-type "text/plain") ("Youve installed Kaptĉapelo! Good work, guy!")))
2023-08-06 00:07:04 -05:00
(defun 404-response ()
'(404 (:content-type "text/plain") ("No such page.")))
(defun server (env captcha-dir)
2023-08-06 00:07:04 -05:00
(let* ((uri (quri:uri (getf env :request-uri)))
2023-08-08 14:34:49 -05:00
(uri-path (quri:uri-path uri))
2023-08-06 00:07:04 -05:00
(params (quri:uri-query-params uri)))
2023-08-08 14:34:49 -05:00
(format *error-output* "~A" uri-path)
(cond ((string= uri-path "/new")
(new-captcha-response captcha-dir))
2023-08-08 14:34:49 -05:00
((or (string= uri-path "/")
(string= uri-path "/index.html"))
2023-08-06 00:07:04 -05:00
(index-response))
2023-08-08 14:34:49 -05:00
((str:starts-with? "/captcha/" uri-path)
;; (str:ends-with? ".png" uri-path))
(image-response uri-path captcha-dir))
2023-08-06 00:07:04 -05:00
('t
(404-response)))))
2023-08-06 00:07:04 -05:00
2023-08-08 14:34:49 -05:00
(defun start-server (&key (address "0.0.0.0") (port 5001) (captcha-directory #p"captcha/"))
2023-08-06 00:07:04 -05:00
(clack:clackup
(lambda (env)
2023-08-08 14:34:49 -05:00
(funcall #'server env captcha-directory))
:address address
:port port))