summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Ostler <sostler@deathmachine.local>2010-03-11 08:01:05 -0500
committerScott Ostler <sostler@deathmachine.local>2010-03-11 08:01:05 -0500
commit3d83db95469600000f4fbc1337bfc6aac9efd9a4 (patch)
tree05ba06023a71bc27e04cbb05280f4c96b63bef9d
parente8142b2742433ea26f6434e5933cddea8b4711c2 (diff)
Added upload limits
-rwxr-xr-xsrc/site.clj129
-rwxr-xr-xsrc/utils.clj7
-rwxr-xr-xstatic/js/pichat.js47
3 files changed, 137 insertions, 46 deletions
diff --git a/src/site.clj b/src/site.clj
index be19830..d05686b 100755
--- a/src/site.clj
+++ b/src/site.clj
@@ -4,6 +4,7 @@
java.util.Date
java.util.TimeZone
java.io.File
+ javax.imageio.ImageIO
org.apache.commons.codec.digest.DigestUtils
javax.servlet.http.Cookie
org.antlr.stringtemplate.StringTemplateGroup)
@@ -59,6 +60,7 @@
"http://dump.fm"
"http://localhost:8080"))
+(def *root-directory* (System/getProperty "user.dir"))
(def *image-directory* "images")
(def *avatar-directory* "avatars")
@@ -74,15 +76,23 @@
(defn swap [f]
(fn [& more] (apply f (reverse more))))
+(def YYYYMMDD-format (new SimpleDateFormat "yyyyMMdd"))
+
+(defn today []
+ (.format YYYYMMDD-format (new Date)))
+
(def formatter (new SimpleDateFormat "h:mm EEE M/d"))
(defn non-empty-string? [s]
(and s (> (count s) 0)))
-(defn rel-join [& more]
- (str-join (System/getProperty "file.separator")
- (cons (System/getProperty "user.dir")
- more)))
+(defn open-file [dir-comps filename]
+ (let [d (str-join (System/getProperty "file.separator")
+ (cons *root-directory* dir-comps))
+ f (str-join (System/getProperty "file.separator")
+ [d filename])]
+ (.mkdir (new File d))
+ (new File f)))
(defn sha1-hash [& more]
(DigestUtils/shaHex (apply str more)))
@@ -159,10 +169,13 @@
(vals @(room :users)))))
(defn updates [room since]
- {"users" (prepare-user-list room)
- "messages" (map process-message-for-json
- (new-messages room since))
- "topic" @(room :topic)})
+ (let [m {"users" (prepare-user-list room)
+ "messages" (map process-message-for-json
+ (new-messages room since))}
+ topic @(room :topic)]
+ (if topic
+ (assoc m "topic" topic)
+ m)))
(def *dumps-per-page* 20)
@@ -392,8 +405,8 @@
(.setAttribute st "users" users)
(cond (= offset 0) (.setAttribute st "prev" false)
(= offset 1) (.setAttribute st "prev" "")
- :else (.setAttribute st "prev" (str "/" (- offset 1))))
- (.setAttribute st "next" (str "/" (+ offset 1)))
+ :else (.setAttribute st "prev" (str "/" (dec offset))))
+ (.setAttribute st "next" (str "/" (inc offset)))
(.toString st)))
;; Topics
@@ -420,21 +433,34 @@
[404 "UNKNOWN_ROOM"]))
(defn set-topic! [room topic deadline maker]
- (ref-set (room :topic)
- {:topic topic
- :deadline deadline
- :maker maker}))
+ (dosync (ref-set (room :topic)
+ {:topic topic
+ :deadline deadline
+ :maker maker})))
+
+(defn end-topic! [room]
+ (dosync (ref-set (room :topic) nil)))
(defn validate-set-topic [session params]
(let [room (@rooms (params :room))
topic (params :topic)
- deadline (params :deadline)]
+ deadline (params :deadline)
+ maker (params :maker)]
(cond (not (session :is_admin)) (resp-error "NOT_VIP")
(not (valid-topic? topic)) (resp-error "INVALID_TOPIC")
(not (valid-deadline? deadline)) (resp-error "INVALID_DEADLINE")
(not room) (resp-error "INVALID_ROOM")
+ (not maker) (resp-error "NOT_MAKER")
:else (do
- (dosync (set-topic! room topic deadline (session :nick)))
+ (set-topic! room topic deadline maker)
+ (resp-success "OK")))))
+
+(defn validate-end-topic [session params]
+ (let [room (@rooms (params :room))]
+ (cond (not (session :is_admin)) (resp-error "NOT_VIP")
+ (not room) (resp-error "INVALID_ROOM")
+ :else (do
+ (end-topic! room)
(resp-success "OK")))))
;; Chat
@@ -590,31 +616,60 @@
;; Upload
+(def *max-image-height* 1000)
+(def *max-image-width* 1000)
+(def *vip-max-file-size* (mbytes 5)) ; don't be nuts guys
+(def *max-file-size* (kbytes 250))
+(def *ignore-size-limit-for-vip* true)
(def *avatar-dimensions* [50 50])
-(defn is-image-file? [path]
- true)
+(defn file-size-limit [vip]
+ (if (and *ignore-size-limit-for-vip* vip)
+ *vip-max-file-size*
+ *max-file-size*))
+
+(defn is-file-too-big? [f vip]
+ (let [limit (file-size-limit vip)]
+ (if (> (.length f) limit)
+ (str "FILE_TOO_BIG " (limit vip)))))
-(defn format-filename [s]
+(defn is-image-invalid? [f]
+ (try
+ (let [i (ImageIO/read f)
+ height (.getHeight i)
+ width (.getWidth i)]
+ (if (or (> width *max-image-width*)
+ (> height *max-image-height*))
+ (str "INVALID_RESOLUTION " *max-image-width* " " *max-image-height*)))
+ (catch Exception _ "FILE_NOT_IMAGE")))
+
+(defn format-filename [s nick]
(let [spaceless (.replace s \space \-)
+ nick-clean (re-gsub #"[^A-Za-z0-9]" "" nick)
subbed (re-gsub #"[^\w.-]" "" spaceless)]
- (str (System/currentTimeMillis) "-" subbed)))
+ (str-join "-" [(System/currentTimeMillis) nick-clean subbed])))
-(defn image-url-from-file [d f]
- (str-join "/" [*server-url* d (.getName f)]))
+(defn image-url-from-file [dir date file]
+ (str-join "/" [*server-url* dir date (.getName file)]))
+(defn validate-upload [f vip]
+ (or (is-file-too-big? f vip)
+ (is-image-invalid? f)))
(defn do-upload [session image room]
- (let [filename (format-filename (:filename image))
- dest (File. (rel-join *image-directory* filename))
- url (image-url-from-file "images" dest)
- msg-id (msg-db (session :user_id) (room :room_id) url)
- msg (struct message-struct (session :nick) url (new Date) msg-id)]
- (do
- (dosync
- (add-message msg room))
- (copy (:tempfile image) dest)
- (resp-success url))))
+ (if-let [err (validate-upload (image :tempfile) (session :is_admin))]
+ (resp-error err)
+ (let [filename (format-filename (:filename image) (session :nick))
+ date (today)
+ dest (open-file [*image-directory* date] filename)
+ url (image-url-from-file "images" date dest)
+ msg-id (msg-db (session :user_id) (room :room_id) url)
+ msg (struct message-struct (session :nick) url (new Date) msg-id)]
+ (do
+ (dosync
+ (add-message msg room))
+ (copy (:tempfile image) dest)
+ (resp-success url)))))
(defn upload [session params]
(let [room-key (params :room)
@@ -622,7 +677,6 @@
image (params :image)]
(cond (not nick) [200 "NOT_LOGGED_IN"]
(not image) [200 "INVALID_REQUEST"]
- (not (is-image-file? (image :filename))) [200 "INVALID_IMAGE"]
(not (validate-room-access room-key session)) [200 "UNKNOWN_ROOM"]
:else (do-upload session image (@rooms room-key)))))
@@ -632,9 +686,10 @@
;; N.B. -- Upload responses aren't JSON-evaluated
(defn do-upload-avatar [session image]
- (let [filename (format-filename (:filename image))
- dest (File. (rel-join *avatar-directory* filename))
- url (image-url-from-file "avatars" dest)]
+ (let [filename (format-filename (:filename image) (session :nick))
+ date (today)
+ dest (open-file [*avatar-directory* date] filename)
+ url (image-url-from-file "avatars" date dest)]
(do
(copy-and-resize (:tempfile image) dest)
(update-user-db (session :user_id) "avatar" url)
@@ -645,7 +700,6 @@
(let [image (params :image)]
(cond (not image) [200 "INVALID_REQUEST"]
(not (session :nick)) [200 "NOT_LOGGED_IN"]
- (not (is-image-file? (image :filename))) [200 "INVALID_IMAGE"]
:else (do-upload-avatar session image))))
;; 404
@@ -701,6 +755,7 @@
(POST "/update-profile" (update-profile session params))
(GET "/topic-list" (validate-topic-list session))
(POST "/set-topic" (validate-set-topic session params))
+ (POST "/end-topic" (validate-end-topic session params))
(GET "/directory" (directory session 0))
(GET "/directory/:offset"
(directory session (maybe-parse-int (-> request :route-params :offset) 0)))
diff --git a/src/utils.clj b/src/utils.clj
index 3180e89..7abed4f 100755
--- a/src/utils.clj
+++ b/src/utils.clj
@@ -13,6 +13,13 @@
:user "postgres"
:password "root"}))
+
+(defn kbytes [b]
+ (* b 1024))
+
+(defn mbytes [b]
+ (* b 1024 1024))
+
;; JSON responses
(def yyyy-mm-dd-formatter (new SimpleDateFormat "yyyy-MM-dd"))
diff --git a/static/js/pichat.js b/static/js/pichat.js
index fd33729..7314ff8 100755
--- a/static/js/pichat.js
+++ b/static/js/pichat.js
@@ -215,12 +215,25 @@ function isSameTopic(curTopic, newTopic) {
}
}
+function displayNewTopic(topic) {
+ $('#topic').empty()
+ .append(topic.topic)
+ .append(topic.deadline)
+ .append(topic.maker).show();
+}
+
+function hideTopic(topic) {
+ $('#topic').empty().hide();
+}
+
function updateTopic(newTopic) {
+ if ($('#topic').length == 0) { return; }
if (isSameTopic(CurrentTopic, newTopic)) { return; }
- alert('new topic');
- CurrentTopic = newTopic;
- $('#topic').text(topic.topic);
-
+ if (newTopic) {
+ displayNewTopic(newTopic);
+ } else {
+ hideTopic();
+ }
}
function refresh() {
@@ -366,13 +379,29 @@ function favoriteImage() {};
function setupUpload(elementId, roomKey) {
var onSubmit = function(file, ext) {
if (!(ext && /^(jpg|png|jpeg|gif|bmp)$/i.test(ext))) {
- alert('SORRY, NOT AN IMAGE DUDE... ');
- return false;
+ alert('SORRY, NOT AN IMAGE DUDE... ');
+ return false;
}
};
var onComplete = function(file, response) {
- if (typeof pageTracker !== 'undefined') {
- pageTracker._trackEvent('Message', 'Upload', typeof Room !== 'undefined' ? Room : 'UnknownRoom');
+ if (response.match(/FILE_TOO_BIG/)) {
+ var maxSize = response.split(" ")[1] / 1024;
+ alert("Sorry. Your file is just too fucking big. "
+ + maxSize + "KB or less please.");
+ return;
+ } else if (response.match(/FILE_NOT_IMAGE/)) {
+ alert("What did you upload? Doesn't seem like an image. Sorry.");
+ return;
+ } else if (response.match(/INVALID_RESOLUTION/)) {
+ var maxWidth = response.split(" ")[1];
+ var maxHeight = response.split(" ")[2];
+ alert("Sorry, the maximum image resolution is "
+ + maxWidth + "x" + maxHeight);
+ return;
+ }
+ if (typeof pageTracker !== 'undefined') {
+ var room = typeof Room !== 'undefined' ? Room : 'UnknownRoom'
+ pageTracker._trackEvent('Message', 'Upload', room);
}
}
new AjaxUpload(elementId, {
@@ -380,7 +409,7 @@ function setupUpload(elementId, roomKey) {
autoSubmit: true,
name: 'image',
data: { room: roomKey },
- onSubmit: onSubmit,
+ onSubmit: onSubmit,
onComplete: onComplete
});
}