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))))))
|