static void user(int argc, char **argv)
{
    HttpAuth    *auth;
    HttpUser    *user;
    MprJson     *credentials;
    char        *password;
    cchar       *cmd, *def, *key, *username, *encodedPassword, *roles;

    if ((auth = app->route->auth) == 0) {
        fail("Authentication not configured in package.json");
        return;
    }
    if (argc < 2) {
        usageError();
        return;
    }
    cmd = argv[0];
    username = argv[1];

    if (smatch(cmd, "remove")) {
        if (httpRemoveUser(app->route->auth, username) < 0) {
            fail("Cannot remove user %s", username);
            return;
        }
        key = sfmt("app.http.auth.users.%s", username);
        if (mprRemoveJson(app->config, key) < 0) {
            fail("Cannot remove %s", key);
            return;
        }
        if (!app->noupdate) {
            savePackage();
            trace("Remove", "User %s", username);
        }
        return;

    } else if (smatch(cmd, "add") || smatch(cmd, "compute")) {
        if (argc < 3) {
            usageError();
            return;
        }
        password = argv[2];
        if (smatch(password, "-")) {
            password = getPassword();
        }
        if (auth->realm == 0 || *auth->realm == '\0') {
            fail("An authentication realm has not been defined. Define a \"app.http.auth.realm\" value.");
            return;
        }
        if (smatch(app->cipher, "md5")) {
            encodedPassword = mprGetMD5(sfmt("%s:%s:%s", username, auth->realm, password));
        } else {
            /* This uses the more secure blowfish cipher */
            encodedPassword = mprMakePassword(sfmt("%s:%s:%s", username, auth->realm, password), 16, 128);
        }
        serase(password);
        if (smatch(cmd, "add")) {
            def = sfmt("{password:'%s',roles:[%s]}", encodedPassword, sjoinArgs(argc - 3, (cchar**) &argv[3], ","));
            credentials = mprParseJson(def);
            key = sfmt("app.http.auth.users.%s", username);
            if (mprWriteJsonObj(app->config, key, credentials) < 0) {
                fail("Cannot update %s", key);
                return;
            }
            savePackage();
            if (!app->noupdate) {
                trace("Update", "User %s", username);
            }
        }
        if (smatch(cmd, "compute") || app->show) {
            trace("Info", "%s %s %s", username, encodedPassword, sjoinArgs(argc - 3, (cchar**) &argv[3], " "));
        }

    } else if (smatch(cmd, "show")) {
        if ((user = httpLookupUser(app->route->auth, username)) == 0) {
            fail("Cannot find user %s", username);
            return;
        }
        roles = sreplace(user->roles, ",", "");
        roles = sreplace(roles, "  ", " ");
        roles = strim(roles, " ", 0);
        trace("Info", "%s %s %s", user->name, user->password, roles);
    }
}
static void user(int argc, char **argv)
{
    HttpAuth    *auth;
    HttpUser    *user;
    MprJson     *credentials;
    char        *password;
    cchar       *cmd, *def, *key, *username, *encodedPassword, *roles;

    if ((auth = app->route->auth) == 0) {
        fail("Authentication not configured in package.json");
        return;
    }
    if (argc < 2) {
        usageError();
        return;
    }
    cmd = argv[0];
    username = argv[1];

    if (smatch(cmd, "remove")) {
        if (httpRemoveUser(app->route->auth, username) < 0) {
            fail("Cannot remove user %s", username);
            return;
        }
        key = sfmt("app.http.auth.users.%s", username);
        if (mprRemoveJson(app->config, key) < 0) {
            fail("Cannot remove %s", key);
            return;
        }
        if (!app->noupdate) {
            savePackage();
            trace("Remove", "User %s", username);
        }
        return;

    } else if (smatch(cmd, "add") || smatch(cmd, "compute")) {
        if (argc < 3) {
            usageError();
            return;
        }
        password = argv[2];
        if (smatch(password, "-")) {
            password = getPassword();
        }
        if (auth->realm == 0 || *auth->realm == '\0') {
            fail("An authentication realm has not been defined. Define a \"app.http.auth.realm\" value.");
            return;
        }
        if (smatch(app->cipher, "md5")) {
            encodedPassword = mprGetMD5(sfmt("%s:%s:%s", username, auth->realm, password));
        } else {
             
            encodedPassword = mprMakePassword(sfmt("%s:%s:%s", username, auth->realm, password), 16, 128);
        }
        serase(password);
        if (smatch(cmd, "add")) {
            def = sfmt("{password:'%s',roles:[%s]}", encodedPassword, sjoinArgs(argc - 3, (cchar**) &argv[3], ","));
            credentials = mprParseJson(def);
            key = sfmt("app.http.auth.users.%s", username);
            if (mprWriteJsonObj(app->config, key, credentials) < 0) {
                fail("Cannot update %s", key);
                return;
            }
            savePackage();
            if (!app->noupdate) {
                trace("Update", "User %s", username);
            }
        }
        if (smatch(cmd, "compute") || app->show) {
            trace("Info", "%s %s %s", username, encodedPassword, sjoinArgs(argc - 3, (cchar**) &argv[3], " "));
        }

    } else if (smatch(cmd, "show")) {
        if ((user = httpLookupUser(app->route->auth, username)) == 0) {
            fail("Cannot find user %s", username);
            return;
        }
        roles = sreplace(user->roles, ",", "");
        roles = sreplace(roles, "  ", " ");
        roles = strim(roles, " ", 0);
        trace("Info", "%s %s %s", user->name, user->password, roles);
    }
}