Beispiel #1
0
def main(args, opts):
    jdb.reset_encoding(sys.stdout, 'utf-8')
    errs = []
    chklist = {}
    try:
        form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform()
    except Exception as e:
        jmcgi.err_page([str(e)])
    fv = form.getfirst
    fl = form.getlist

    if not sess or sess.priv != 'A': users = []
    else:
        sql = "SELECT * FROM users ORDER BY userid"
        sesscur = jdb.dbOpenSvc(cfg, svc, session=True, nokw=True)
        users = jdb.dbread(sesscur, sql)
        L('cgi.users').debug('read %d rows from table "user"' % (len(users), ))
    jmcgi.jinja_page("users.jinja",
                     users=users,
                     session=sess,
                     cfg=cfg,
                     parms=parms,
                     svc=svc,
                     dbg=dbg,
                     sid=sid,
                     this_page='user.py',
                     result=fv('result'))
Beispiel #2
0
def get_user(uid, svc, cfg):
    cur = jdb.dbOpenSvc(cfg, svc, session=True, nokw=True)
    sql = "SELECT * FROM users WHERE userid=%s"
    users = jdb.dbread(cur, sql, (uid, ))
    # 'userid' is primary key of users table so we should never
    # receive more than one row.
    assert len(users) <= 1, "Too many rows received"
    return users[0] if users else None
Beispiel #3
0
def main(args, opts):
    jdb.reset_encoding(sys.stdout, 'utf-8')
    errs = []
    so = None
    stats = {}
    try:
        form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform()
    except Exception as e:
        jmcgi.err_page([str(e)])
    fv = form.getfirst
    fl = form.getlist

    # The form values "userid", "fullname", "email", "priv",
    #  "disabled", come from editable fields in the user.py
    #  page.
    # The values "new" (i.e. create) and "delete" are also user
    #  boolean input from user.py indicating what the user wants
    #  to do.  Neither of them set indicates an update action on
    #  an existing account.  Both of them set is an error.
    # The form value "subjid" identifies the user whose data was
    #  originally loaded into the user.py form and is the user any
    #  update or delete will be performed on.  If it differs from
    #  sess.userid it indcates the action is to e done on the
    #  account of someone other than the logged user themself
    #  and is prohibited unless the logged in user has "admin"
    #  privilege.  For a new (create) action, "subjid" is ignored
    #  and the new user is created with the id given in "userid".

    # Set 'action' to "n" (new), "u" (update), "d" (delete) or
    #  "x" (invalid) according to the values of fv('new') and
    #  fv('delete') that were received from as url parameters
    #  from the User form.
    action = {(0,0):'u', (0,1):'d', (1,0):'n', (1,1):'x'}\
               [(bool(fv('new')),bool(fv('delete')))]
    L('cgi.userupd').debug(
        "new=%r, delete=%r, action=%r, subjid=%r, userid=%r" %
        (fv('new'), fv('delete'), action, fv('subjid'), fv('userid')))

    # NOTE: The jmcgi.err_page() calls below do not return,
    #  jmcgi.err_page() calls sys.exit().

    if not sess:
        jmcgi.err_page([],
                       prolog="<p>You must login before you can change your "
                       "user settings.</p>")
    if fv('subjid') != sess.userid and sess.priv != 'A':
        jmcgi.err_page(
            [],
            prolog="<p>You do not have sufficient privilege to alter "
            "settings for anyone other than yourself.</p>")
    if action in ('nd') and sess.priv != 'A':
        jmcgi.err_page(
            [],
            prolog="<p>You do not have sufficient privilege to create "
            "or delete users.</p>")
    if action == 'x':
        jmcgi.err_page(
            [], prolog="<p>\"New user\" and \"Delete\" are incompatible.</p>")

    errors = []
    # Get the id of the user we will be updating.  If creating a
    # new user, 'subjid' should not exist and thus 'subj' will be
    # None which has the beneficial effect of causing gen_sql_-
    # params() to generate change parameters for every form value
    # which is what we want when creating a user.
    subj = jmcgi.get_user(fv('subjid'), svc, cfg)
    if action in 'nu':  # "new" or "update" action...
        if action == 'u':
            L('cgi.userupd').debug("update user %r" % sanitize_o(subj))
        else:
            L('cgi.userupd').debug("create user %r" % fv('userid'))
        if action == 'n' and \
                (subj or fv('userid')==sess.userid
                 or jmcgi.get_user(fv('userid'), svc, cfg)):
            # This is the creation of a new user (fv('userid')).
            # The userid must not already exist.  The tests for
            # subj and sess.userid are simply to avoid an expensive
            # get_user() call when we already know the user exists.
            errors.append("Account name %s is already in use." % fv('userid'))
        if action == 'u' and fv('userid')!=subj.userid \
                and (fv('userid')==sess.userid \
                     or jmcgi.get_user(fv('userid'), svc, cfg)):
            # This is an update of an existing user.
            # If the new userid (fv('userid')) is the same as the
            # subj.userid it's not being changed and is ok.  If
            # different then it must not be the same as an exiting
            # userid.  The test for sess.userid is simply to avoid
            # an expensive get_user() call when we already know
            # that user exists.
            errors.append("Account name %s is already in use." % fv('userid'))

        # Get the parameters we'll need for the sql statement used
        # to update the user/sessions database.
        collist, values, err \
            = gen_sql_params (sess.priv=='A', subj, fv('pw1'), fv('pw2'),
                              fv('userid'), fv('fullname'), fv('email'),
                              fv('priv'), fv('disabled'))
        errors.extend(err)
        L('cgi.userupd').debug("collist: %r" % collist)
        L('cgi.userupd').debug("values: %r" % sanitize_v(values, collist))

    else:  # "delete" action...
        # We ignore changes made to the form fields since we
        # are going to delete the user, they are irrelevant.
        # Except for one: the "userid" field.  If that was
        # changed we treat it as an error due to the risk that
        # the user thought the changed userid will be deleted
        # which is not what will happen (we delete the "subjid"
        # user.)
        values = []
        if fv('userid') != fv('subjid'):
            errors.append("Can't delete user when userid has been changed.")
        if not subj:
            errors.append("User '%s' doesn't exist." % fv('subjid'))

    if errors:
        jmcgi.err_page(
            errs=errors,
            prolog="The following errors were found in the changes "
            "you requested.  Please use your browser's Back button "
            "to return to the user page, correct them, and resubmit "
            "your changes.")

    update_session = None
    result = None
    summary = 'not available'
    if action == 'n':  # Create new user...
        cols = ','.join(c for c, p in collist)
        pmarks = ','.join(p for c, p in collist)
        sql = "INSERT INTO users(%s) VALUES (%s)" % (cols, pmarks)
        values_sani = sanitize_v(values, collist)
        summary = "added user \"%s\"" \
                  % ''.join(p for c,p in collist if c=='userid')
    elif action == 'd':  # Delete existing user...
        sql = "DELETE FROM users WHERE userid=%s"
        values.append(fv('subjid'))
        values_sani = values
        summary = "deleted user \"%s\"" % fv('subjid')
    else:  # Update existing user...
        if not collist: result = 'nochange'
        else:
            if subj and subj.userid == sess.userid \
                    and fv('userid') and fv('userid'):
                update_session = fv('userid')
            updclause = ','.join(("%s=%s" % (c, p)) for c, p in collist)
            sql = "UPDATE users SET %s WHERE userid=%%s" % updclause
            values.append(fv('subjid'))
            values_sani = sanitize_v(values, collist)
            summary = "updated user %s (%s)" \
                       % (fv('subjid'), ','.join([c for c,p in collist]))

    if result != 'nochange':
        sesscur = jdb.dbOpenSvc(cfg, svc, session=True, nokw=True)
        L('cgi.userupd.db').debug("sql:  %r" % sql)
        # 'values_sani' should be the same as values but with any
        # password text masked out.
        L('cgi.userupd.db').debug("args: %r" % values_sani)
        sesscur.execute(sql, values)
        sesscur.connection.commit()
        #FIXME: trap db errors and try to figure out what went
        # wrong in terms that a user can remediate.
        if update_session:
            L('cgi.userupd').debug("update sess.userid: %r->%r" %
                                   (sess.userid, update_session))
            sess.userid = update_session
        L('cgi.userupd').info(summary)
        result = 'success'
    # If the user is not an admin we send them back to their
    # settings page (using 'userid' since it they may have changed
    # it.)  For admin users it's more complcatd because they might
    # have deleted the user.  Easiest for us to send him/her back
    # to the user list page which we know always exists.
    if sess.priv == 'A': return_to = 'users.py?'
    else:
        return_to = 'user.py?u=%s' % fv('userid')
    jmcgi.redirect(urlbase() + "%s&svc=%s&sid=%s&dbg=%s&result=%s" %
                   (return_to, svc, sid, dbg, result))
Beispiel #4
0
def parseform(readonly=False):
    """\
    Do some routine tasks that are needed for (most) every page,
    specifically:
    * Call cgi.FieldStorage to parse parameters.
    * Extract the svc parameter, validate it, and open the requested database.
    * Get session id and handle log or logout requests.
    Return an 8-tuple of:
        form (cgi.FieldStorage obj)
        svc (string) -- Checked svc value.
        dbg (int) -- true if "dbg" url param has true value, else 0.
        cur (dbapi cursor) -- Open cursor for database defined by 'svc'.
        sid (string) -- session.id in hexidecimal form or "".
        sess (Session inst.) -- Session for sid or None.
        params (dict) -- Received and decoded form parameters.
        cfg (Config inst.) -- Config object from reading config.ini.
        """

    cfg = initcgi("config.ini")  # Read config, initialize logging.
    L('cgi.jmcgi').debug("parseform: called in %s" %
                         sys.modules['__main__'].__file__)
    errs = []
    sess = None
    sid = ''
    cur = None
    svc = None
    def_svc = cfg['web'].get('DEFAULT_SVC', 'jmdict')
    if def_svc.startswith('db_'): def_svc = def_svc[3:]
    check_server_status(cfg.get('web', 'STATUS_DIR'))

    form = cgi.FieldStorage()
    L('cgi.jmcgi').debug("query_string: %s" % os.environ.get('QUERY_STRING'))
    for k in form.keys():
        v = ['***']*len(form.getlist(k)) if k in ('password','pw1','pw2') \
                                         else form.getlist(k)
        L('cgi.jmcgi').debug("parseform: form key %s=%r" % (k, v))
    dbg = int(form.getfirst('dbg') or '0')
    svc = form.getfirst('svc') or def_svc
    #L('cgi.jmcgi').debug("parseform: svc=%s" % svc)
    usid = form.getfirst('sid') or ''  # No SID is "", not None.
    try:
        svc = safe(svc)
    except ValueError:
        errs.append('svc=' + svc)
    if not errs:
        try:
            cur = jdb.dbOpenSvc(cfg, svc)
        except KeyError as e:
            errs.append('svc=' + str(e))
    if errs: raise ValueError(';'.join(errs))

    # Login, logout, and session identification...
    scur = jdb.dbOpenSvc(cfg, svc, session=True, nokw=True)
    action = form.getfirst('loginout')  # Will be None, "login" or "logout"
    sid = get_sid_from_cookie() or ''
    sid_from_cookie = bool(sid)
    if usid: sid = usid  # Use sid from url if available.
    L('cgi.jmcgi').debug("parseform: sid=%s, from_cookie=%s, action=%s" %
                         (sid, sid_from_cookie, action))
    uname = form.getfirst('username') or ''
    pw = form.getfirst('password') or ''
    sid, sess = get_session(scur, action, sid, uname, pw)
    L('cgi.jmcgi').debug("parseform: %s session, sid=%s" %
                         ("got" if sess else "no", sid))
    if sid: set_sid_cookie(sid, delete=(action == "logout"))
    if sid_from_cookie: sid = ''
    scur.connection.close()

    # Collect the form parameters.  Caller is expected to pass
    # them to the page template which will use them in the login
    # section as hidden parms so the page can be recreated after
    # a login.  We leave out any param name "result" since that
    # is used as a confirmation message by the userupd.py page
    # and best to see it only once.
    parms = [(k, v) for k in list(form.keys())
             if k not in ('loginout', 'username', 'password', 'result')
             for v in form.getlist(k)]

    return form, svc, dbg, cur, sid, sess, parms, cfg