|
@@ -270,18 +270,23 @@ is replaced with replacement."
|
|
|
(subseq (crypto:hmac-digest hmac) 0 hmac-length))))
|
|
(subseq (crypto:hmac-digest hmac) 0 hmac-length))))
|
|
|
|
|
|
|
|
(defun encode-callback-data (chat-id section data &optional (ttl 600) (hmac-length 12))
|
|
(defun encode-callback-data (chat-id section data &optional (ttl 600) (hmac-length 12))
|
|
|
- (let ((message (format nil "~A:~A:~A:~A"
|
|
|
|
|
- (base64:integer-to-base64-string chat-id) section data
|
|
|
|
|
- (base64:integer-to-base64-string
|
|
|
|
|
- (+ ttl (local-time:timestamp-to-universal (local-time:now)))))))
|
|
|
|
|
- (format nil "~A$~A"
|
|
|
|
|
- message (token-hmac message hmac-length))))
|
|
|
|
|
|
|
+ (when (find #\: data)
|
|
|
|
|
+ (error "Bad data."))
|
|
|
|
|
+ (let* ((message (format nil "~A:~A:~A:~A"
|
|
|
|
|
+ (base64:integer-to-base64-string chat-id)
|
|
|
|
|
+ (base64:integer-to-base64-string
|
|
|
|
|
+ (+ ttl (local-time:timestamp-to-universal (local-time:now))))
|
|
|
|
|
+ section data))
|
|
|
|
|
+ (encoded (format nil "~A$~A" message (token-hmac message hmac-length))))
|
|
|
|
|
+ (when (> (length encoded) +telegram-max-callback-data-length+)
|
|
|
|
|
+ (error "Max callback length exceeded"))
|
|
|
|
|
+ encoded))
|
|
|
|
|
|
|
|
(defun decode-callback-data (chat-id raw-data &optional (hmac-length 12))
|
|
(defun decode-callback-data (chat-id raw-data &optional (hmac-length 12))
|
|
|
(destructuring-bind (message hmac)
|
|
(destructuring-bind (message hmac)
|
|
|
(split-sequence:split-sequence #\$ raw-data :from-end t :count 2)
|
|
(split-sequence:split-sequence #\$ raw-data :from-end t :count 2)
|
|
|
- (destructuring-bind (cid section data expire)
|
|
|
|
|
- (split-sequence:split-sequence #\: message)
|
|
|
|
|
|
|
+ (destructuring-bind (cid expire section data)
|
|
|
|
|
+ (split-sequence:split-sequence #\: message :count 4)
|
|
|
(unless (= chat-id (base64:base64-string-to-integer cid))
|
|
(unless (= chat-id (base64:base64-string-to-integer cid))
|
|
|
(error "Wrong chat id."))
|
|
(error "Wrong chat id."))
|
|
|
(unless (>= (base64:base64-string-to-integer expire)
|
|
(unless (>= (base64:base64-string-to-integer expire)
|
|
@@ -289,7 +294,7 @@ is replaced with replacement."
|
|
|
(error "Expired."))
|
|
(error "Expired."))
|
|
|
(unless (equal hmac (token-hmac message hmac-length))
|
|
(unless (equal hmac (token-hmac message hmac-length))
|
|
|
(error "Bad data."))
|
|
(error "Bad data."))
|
|
|
- (values data section))))
|
|
|
|
|
|
|
+ (values data (intern (string-upcase section) "KEYWORD")))))
|
|
|
|
|
|
|
|
(defmacro def-message-handler (name (message) &body body)
|
|
(defmacro def-message-handler (name (message) &body body)
|
|
|
`(progn
|
|
`(progn
|
|
@@ -326,6 +331,35 @@ is replaced with replacement."
|
|
|
,@body
|
|
,@body
|
|
|
t)))))
|
|
t)))))
|
|
|
|
|
|
|
|
|
|
+(defmacro def-callback-handler (name (callback) &body body)
|
|
|
|
|
+ `(progn
|
|
|
|
|
+ (defun ,name (,callback)
|
|
|
|
|
+ (let* ((query-id (aget "id" ,callback))
|
|
|
|
|
+ (from (aget "from" ,callback))
|
|
|
|
|
+ (raw-data (aget "data" ,callback))
|
|
|
|
|
+ (message (aget "message" ,callback))
|
|
|
|
|
+ (inline-message-id (aget "inline_message_id" ,callback))
|
|
|
|
|
+ (from-id (aget "id" from))
|
|
|
|
|
+ (chat-id (aget "id" (aget "chat" message)))
|
|
|
|
|
+ (message-id (aget "message_id" message)))
|
|
|
|
|
+ (declare (ignorable query-id from raw-data message inline-message-id from-id chat-id message-id))
|
|
|
|
|
+ (handler-case (progn ,@body)
|
|
|
|
|
+ (error (e)
|
|
|
|
|
+ (log:error "~A" e)
|
|
|
|
|
+ (bot-send-message (or chat-id from-id)
|
|
|
|
|
+ (format nil "Ошибочка вышла~@[: ~A~]"
|
|
|
|
|
+ (when (member chat-id *admins*) e)))))))
|
|
|
|
|
+ (add-hook :update-callback-query ',name)))
|
|
|
|
|
+
|
|
|
|
|
+(defmacro def-callback-section-handler (name (&rest sections) &body body)
|
|
|
|
|
+ `(def-callback-handler ,name (callback)
|
|
|
|
|
+ (when chat-id
|
|
|
|
|
+ (multiple-value-bind (data section) (decode-callback-data chat-id raw-data)
|
|
|
|
|
+ (when (member section (list ,@sections))
|
|
|
|
|
+ (log:info query-id from-id chat-id message-id section data)
|
|
|
|
|
+ ,@body
|
|
|
|
|
+ t)))))
|
|
|
|
|
+
|
|
|
;; Schedule
|
|
;; Schedule
|
|
|
(defmacro defcron (name (&rest schedule) &body body)
|
|
(defmacro defcron (name (&rest schedule) &body body)
|
|
|
(let ((schedule (or schedule '(:minute '* :hour '*))))
|
|
(let ((schedule (or schedule '(:minute '* :hour '*))))
|