/*
 * This example defines two groups of roles any user/group can be assigned to.
 * An "admin" role which grants full access to all APIs on all objects to its
 * members, and other roles which allows their members to all APIs defined in
 * restrictedActions on domains matching a regular expressions assigned to
 * each role. (Jump below the Role class definition to see them.) Users who
 * belong to an "operator" role can act on any domain (matching ".*" RE),
 * while members of "userA", "userB", and "userC" roles are limited by more
 * specific REs.
 *
 * A virtualization host admin would define domains with names prefixed by
 * customer names and create a separate role for each customer restricting
 * its members to manage only domains with the corresponding prefix.
 */

function Role(name) {
    this.name = name;

    this.users = [];
    this.groups = [];

    this.check = function(subject, api, domain) {
        var validUser = false

        if (this.users.indexOf(subject.user) >= 0) {
            validUser = true;
        } else {
            for (var i = 0; i < subject.groups.length; i++) {
                if (this.groups.indexOf(subject.groups[i]) >= 0) {
                    validUser = true;
                    break;
                }
            }
        }

        if (validUser &&
            (this.name == "admin" ||
             !domain ||
             (this.domains && domain.match(this.domains)))) {
            var msg = "Access granted: " +
                      "user = " + subject.user +
                      ", groups = [" + subject.groups + "]" +
                      ", role = " + this.name +
                      ", api = " + api;
            if (domain)
                msg += ", domain = " + domain;
            polkit.log(msg);
            return true
        }

        return false;
    };
}


/* Basic operations and monitoring on a limited set of domains. */
var userA = new Role("userA");
userA.domains = /^a/;
userA.users = ["userA1", "userA2", "userA3", "multiUser"];
userA.groups = ["groupA1", "groupA2"];

var userB = new Role("userB");
userB.domains = /^b/;
userB.users = ["userB1", "userB2", "userB3", "multiUser"];
userB.groups = ["groupB1", "groupB2", "multiGroup"];

var userC = new Role("userC");
userC.domains = /^c/;
userC.users = ["userC1", "userC2", "userC3"];
userC.groups = ["groupC1", "groupC2", "multiGroup"];

/* Same as users but on any domain. */
var operator = new Role("operator");
operator.domains = /.*/;
operator.users = ["powerUser1", "powerUser2"];
operator.groups = ["powerGroup1", "powerGroup2", "powerGroup3"];

var users = [operator, userA, userB, userC];

/* Full access. */
var admin = new Role("admin");
admin.users = ["adminUser1"];
admin.groups = ["adminGroup1"];


restrictedActions = [
    "domain.core-dump",
    "domain.fs-freeze",
    "domain.fs-trim",
    "domain.getattr",
    "domain.hibernate",
    "domain.init-control",
    "domain.inject-nmi",
    "domain.open-device",
    "domain.open-graphics",
    "domain.pm-control",
    "domain.read",
    "domain.reset",
    "domain.save",
    "domain.screenshot",
    "domain.send-input",
    "domain.send-signal",
    "domain.set-password",
    "domain.set-time",
    "domain.snapshot",
    "domain.start",
    "domain.stop",
    "domain.suspend"
];

polkit.addRule(function(action, subject) {
    if (action.id.indexOf("org.libvirt.api.") != 0)
        return polkit.Result.NOT_HANDLED;

    var api = action.id.replace("org.libvirt.api.", "");
    var domain = action.lookup("domain_name");

    if (admin.check(subject, api, domain))
        return polkit.Result.YES;

    if (restrictedActions.indexOf(api) < 0)
        return polkit.Result.NOT_HANDLED;

    for (var i = 0; i < users.length; i++) {
        if (users[i].check(subject, api, domain))
            return polkit.Result.YES;
    }

    return polkit.Result.NO;
});
