Generating UNIX passwords
authoradamch <adamch>
Sun, 18 Nov 2007 22:35:09 +0000 (22:35 +0000)
committeradamch <adamch>
Sun, 18 Nov 2007 22:35:09 +0000 (22:35 +0000)
app.sig
app.sml
app/app.sig
app/app.sml
app/confirm.mlt
app/join.mlt
tables.sql

diff --git a/app.sig b/app.sig
index e169a44..3842d29 100644 (file)
--- a/app.sig
+++ b/app.sig
@@ -16,7 +16,7 @@ sig
                 passwd : string, status : status, applied : Init.C.timestamp,
                 ipaddr : string option,
                 confirmed : Init.C.timestamp option, decided : Init.C.timestamp option,
-                msg : string }
+                msg : string, unix_passwd : string }
 
     val lookupApp : int -> app
     val listApps : status -> app list
@@ -29,4 +29,4 @@ sig
     val approve : int * string -> bool
     val add : int -> unit
     val abortAdd : int -> unit
-end
\ No newline at end of file
+end
diff --git a/app.sml b/app.sml
index 5d54768..15727a6 100644 (file)
--- a/app.sml
+++ b/app.sml
@@ -32,10 +32,10 @@ type app = { id : int, name : string, rname : string, gname : string option, ema
             forward : bool, uses : string, other : string,
             passwd : string, status : status, applied : C.timestamp, ipaddr : string option,
             confirmed : C.timestamp option, decided : C.timestamp option,
-            msg : string}
+            msg : string, unix_passwd : string}
 
 fun mkAppRow [id, name, rname, gname, email, forward, uses, other, passwd, status,
-             applied, ipaddr, confirmed, decided, msg] =
+             applied, ipaddr, confirmed, decided, msg, unix_passwd] =
     { id = C.intFromSql id, name = C.stringFromSql name, rname = C.stringFromSql rname,
       gname = (if C.isNull gname then NONE else SOME (C.stringFromSql gname)),
       email = C.stringFromSql email, forward = C.boolFromSql forward,
@@ -44,18 +44,20 @@ fun mkAppRow [id, name, rname, gname, email, forward, uses, other, passwd, statu
       ipaddr = (if C.isNull ipaddr then NONE else SOME (C.stringFromSql ipaddr)),
       confirmed = if C.isNull confirmed then NONE else SOME (C.timestampFromSql confirmed),
       decided = if C.isNull decided then NONE else SOME (C.timestampFromSql decided),
-      msg = C.stringFromSql msg}
+      msg = C.stringFromSql msg, unix_passwd = C.stringFromSql unix_passwd}
   | mkAppRow r = rowError ("app", r)
 
 fun lookupApp id =
-    case C.oneOrNoRows (getDb ()) ($`SELECT id, name, rname, gname, email, forward, uses, other, passwd, status, applied, ipaddr, confirmed, decided, msg
+    case C.oneOrNoRows (getDb ()) ($`SELECT id, name, rname, gname, email, forward, uses, other, passwd, status, applied, ipaddr, confirmed, decided,
+                                           msg, unix_passwd
                                     FROM MemberApp
                                     WHERE id = ^(C.intToSql id)`) of
        SOME row => mkAppRow row
       | NONE => raise Fail "Membership application not found"
 
 fun listApps status =
-    C.map (getDb ()) mkAppRow ($`SELECT id, name, rname, gname, email, forward, uses, other, passwd, status, applied, ipaddr, confirmed, decided, msg
+    C.map (getDb ()) mkAppRow ($`SELECT id, name, rname, gname, email, forward, uses, other, passwd, status, applied, ipaddr, confirmed, decided,
+                                       msg, unix_passwd
                                 FROM MemberApp
                                 WHERE status = ^(statusToSql status)
                                   AND NOT (status = 2 AND decided < CURRENT_TIMESTAMP - INTERVAL '1 MONTH')
index 18c259e..7b17423 100644 (file)
@@ -18,5 +18,5 @@ sig
     val validUser : string -> bool
     val userExists : string -> bool
 
-    val confirm : int * string -> bool
-end
\ No newline at end of file
+    val confirm : int * string -> string option
+end
index 62f386a..1346829 100644 (file)
@@ -1,7 +1,7 @@
 structure App :> APP =
 struct
 
-val baseUrl = "http://join.hcoop.net/join/"
+val baseUrl = "https://join.hcoop.net/join/"
 val portalUrl = "https://members2.hcoop.net/portal/"
 
 open Sql
@@ -95,6 +95,18 @@ fun sendMail (to, subj, intro, footer, id) =
 type application = { name : string, rname : string, gname : string option, email : string,
                     forward : bool, uses : string, other : string }
 
+fun randomPassword () =
+    let
+       val proc = Unix.execute ("/usr/bin/apg", ["/usr/bin/apg", "-n", "1", "-m", "10"])
+    in
+       case TextIO.inputLine (Unix.textInstreamOf proc) of
+           NONE => raise Fail "Couldn't execute apg"
+         | SOME line =>
+           case String.tokens Char.isSpace line of
+               [s] => s
+             | _ => raise Fail "Couldn't parse output of apg"
+    end
+
 fun apply {name, rname, gname, email, forward, uses, other} =
     let
        val db = getDb ()
@@ -104,22 +116,24 @@ fun apply {name, rname, gname, email, forward, uses, other} =
            let
                val id = C.intFromSql id
                val passwd = Int.toString (Int.abs (Random.randInt (!rnd)))
+               val unix_passwd = randomPassword ()
            in
-               C.dml db ($`INSERT INTO MemberApp (id, name, rname, gname, email, forward, uses, other, passwd, status, applied, msg)
+               C.dml db ($`INSERT INTO MemberApp (id, name, rname, gname, email, forward, uses, other, passwd, status, applied, msg, unix_passwd)
                            VALUES (^(C.intToSql id), ^(C.stringToSql name), ^(C.stringToSql rname),
                                    ^(case gname of NONE => "NULL" | SOME gname => C.stringToSql gname),
                                    ^(C.stringToSql email), ^(C.boolToSql forward), ^(C.stringToSql uses),
-                                   ^(C.stringToSql other), ^(C.stringToSql passwd), 0, CURRENT_TIMESTAMP, '')`);
+                                   ^(C.stringToSql other), ^(C.stringToSql passwd), 0, CURRENT_TIMESTAMP,
+                                   '', ^(C.stringToSql unix_passwd))`);
                sendMail (email, "Confirm membership application",
-                         "We've received a request to join the Internet Hosting Cooperative (hcoop.net) with this e-mail address.",
+                            "We've received a request to join the Internet Hosting Cooperative (hcoop.net) with this e-mail address.",
                          fn mwrite => (mwrite ("To confirm this application, visit ");
                                        mwrite (baseUrl);
                                        mwrite ("confirm?id=");
                                        mwrite (Int.toString id);
                                        mwrite ("&p=");
-                                       mwrite (passwd);
+                                       mwrite passwd;
                                        mwrite ("\n")),
-                         id)
+                            id)
            end
       | _ => raise Fail "Bad next sequence val"
     end
@@ -154,17 +168,20 @@ fun confirm (id, passwd) =
     let
        val db = getDb ()
     in
-       case C.oneOrNoRows db ($`SELECT id FROM MemberApp WHERE id = ^(C.intToSql id) AND passwd = ^(C.stringToSql passwd) AND status = 0`) of
-           SOME _ =>
+       case C.oneOrNoRows db ($`SELECT unix_passwd FROM MemberApp WHERE id = ^(C.intToSql id) AND passwd = ^(C.stringToSql passwd) AND status = 0`) of
+           SOME [unix_passwd] =>
            (C.dml db ($`UPDATE MemberApp SET status = 1, confirmed = CURRENT_TIMESTAMP WHERE id = ^(C.intToSql id)`);
-            sendMail ("board@hcoop.net",
-                      "New membership application",
-                      "We've received a new request to join hcoop.",
+            if sendMail ("board@hcoop.net",
+                         "New membership application",
+                         "We've received a new request to join hcoop.",
                       fn mwrite => (mwrite ("Open applications: ");
                                     mwrite (portalUrl);
                                     mwrite ("apps")),
-                      id))
-         | NONE => false
+                         id) then
+                SOME (C.stringFromSql unix_passwd)
+            else
+                NONE)
+         | NONE => NONE
     end
 
 end
dissimilarity index 69%
index b0e0187..3492118 100644 (file)
@@ -1,14 +1,16 @@
-<% @header [("title", ["Confirm application"])];
-
-val id = Web.stoi ($"id");
-val passwd = $"p";
-
-if App.confirm (id, passwd) then
-       %><h3><b>Confirmation successful</b></h3>
-       You should hear from us within a few days from now.<%
-else
-       %><h3><b>Error confirming</b></h3>
-       Did you already follow this confirmation link?<%
-end;
-
-@footer[] %>
\ No newline at end of file
+<% @header [("title", ["Confirm application"])];
+
+val id = Web.stoi ($"id");
+val passwd = $"p";
+
+switch App.confirm (id, passwd) of
+         SOME unix_passwd =>
+               %><h3><b>Confirmation successful</b></h3>
+               You should hear from us within a few days from now.  Save this password, to use to access our servers if your application is approved:
+               <blockquote><tt><% Web.html unix_passwd %></tt></blockquote><%
+       | NONE =>
+               %><h3><b>Error confirming</b></h3>
+                       Did you already follow this confirmation link?<%
+end;
+
+@footer[] %>
\ No newline at end of file
index f0a7ec3..40a6f81 100644 (file)
        elseif not (App.validEmail email) then
                %><h3>Invalid e-mail address</h3><%
        elseif not (App.apply { name = name, rname = rname, email = email,
-                               gname = (case gname of "" => NONE | _ => SOME gname),
+                               gname = (case gname of "" => NONE | _ => SOME gname),
                                forward = forward, uses = uses, other = other }) then
                %><h3>Error sending confirmation e-mail</h3><%
        else
-               %><h3>Application recorded</h3>
+               %><h3>Application recorded</h3>
                Check your e-mail for a message with further instructions.<%
        end
 else
index 12e879f..f0067e8 100644 (file)
@@ -13,7 +13,8 @@ CREATE TABLE MemberApp(
        ipaddr TEXT,
        confirmed TIMESTAMP,
        decided TIMESTAMP,
-       msg TEXT NOT NULL);
+       msg TEXT NOT NULL,
+       unix_passwd TEXT NOT NULL);
 
 CREATE SEQUENCE MemberAppSeq START 1;