aboutsummaryrefslogtreecommitdiff
path: root/src/ctf_website/views/new.clj
blob: 860045fa1b1ff9209add225716aaab4786b023fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
(ns ctf-website.views.new
  (:require [ctf-website.views.common :as common])
  (:import java.lang.ProcessBuilder
           [java.util.concurrent Executors TimeUnit])
  (:use [noir.core :only [defpage]]
        [hiccup.core :only [html]]))

(defpage
  "/new" []
  (common/layout
    [:form {:method "POST"
            :action "new"}
     [:p "Username:"
      [:input {:type "text"
               :name "username"}]]
     [:p "Password:"
      [:input {:type "password"
               :name "password"}]]
     [:p
      [:input {:type "submit"
               :value "Create"}]]]))

(def fail
  (common/layout
    [:p "Try a username that doesn't suck."]))

(def throttled
  (common/layout
    [:p "Woah woah woah! Let's not all talk at once."]))

(def good
  (ring.util.response/redirect "login"))

(defonce *barrier* (ref true))
(defonce *timer* (Executors/newScheduledThreadPool 1))

(defpage
  [:post "/new"] {:keys [username password]}
  (let [throttle (ref true)]
    (dosync
      (when (deref *barrier*)
        (ref-set throttle false)
        (ref-set *barrier* false)))
    (if (deref throttle)
      throttled
      (let [_ (.schedule *timer* #(dosync (ref-set *barrier* true))
                         1 (TimeUnit/SECONDS))
            adduser (.start (ProcessBuilder. (list "adduser" username)))
            _ (.close (.getOutputStream adduser))
            retval (.waitFor adduser)]
        (if (not (= 0 retval))
          fail ;; this seems to take care of usernames containing : or \n
          (let [chpasswd (.start (ProcessBuilder. (list "chpasswd")))
                out (.getOutputStream chpasswd)
                userpass (.getBytes (str username ":" password) "UTF-8")
                ;; chpasswd seems to only care about \n, though I only tested
                ;; \n and \r and \0.
                userpass (remove #(= 0x0a %) userpass)
                _ (.write out (into-array Byte/TYPE userpass))
                _ (.close out)
                retval (.waitFor chpasswd)]
            good))))))