ACC SHELL

Path : /usr/share/YaST2/modules/
File Upload :
Current File : //usr/share/YaST2/modules/KeyManager.ycp

/**
 * File:	modules/KeyManager.ycp
 * Package:	GPG Key Management
 * Summary:	Manages GPG keys in the package manager
 * Authors:	Ladislav Slezák <lslezak@novell.com>
 *
 * $Id: KeyManager.ycp 57028 2009-04-29 10:58:09Z lslezak $
 *
 */

{

textdomain "packager";
module "KeyManager";

import "Report";
import "Directory";
import "String";

// the current state
list<map<string,any> > known_keys = [];

// keys to delete
list<map<string,any> > deleted_keys = [];

// keys to import from a file (file name => trusted flag)
list<map<string,any> > import_from_file = [];

boolean modified = false;

//////////////////////////////////////////////////////////////////////////////

/**
 * Reset the internal state of the module. The current configuration and all
 * changes are deleted.
 */
global void Reset()
{
    known_keys = [];
    deleted_keys = [];
    import_from_file = [];
    modified = false;
}

/**
 * Read the current configuration from the package manager
 * @return list the current configuration, nil when an error occurr
 */
list<map<string,any> > ReadCurrentKeys()
{
    // read trusted keys
    list<map<string,any> > ret = Pkg::GPGKeys(true);

    y2milestone("Read configuration: %1", ret);

    return ret;
}


/**
 * Read the current configuration from the package manager. The previous changes are lost (@see Reset).
 * The target system of the package manager must be initialized before reading GPG keys!
 * @return boolean true on success
 */
global boolean Read()
{
    if (size(known_keys) > 0)
    {
	y2warning("Rereading GPG keys from the package manager");
	Reset();
    }

    known_keys = ReadCurrentKeys();

    if (known_keys == nil)
    {
	known_keys = [];
	return false;
    }

    return true;
}

/**
 * Search a GPG key in the known keys
 * @param key_id ID of the key
 * @return map Data about the key or nil if the key was not found
 */
global map<string,any> SearchGPGKey(string key_id)
{
    map<string,any> ret = nil;

    // search the properties of the key
    foreach(map<string,any> key, known_keys,
	{
	    if (key["id"]:"" == key_id)
	    {
		ret = key;
		break;
	    }
	}
    );

    return ret;
}

/**
 * Apply the changes, update the current status
 * @return boolean true on success
 */
global boolean Write()
{
    if (!modified)
    {
	y2milestone("No change, nothing to write");
	return true;
    }

    y2milestone("Writing key management configuration");

    boolean ret = true;

    // delete the keys marked for removal
    foreach(map<string,any> deleted_key, deleted_keys,
	{
	    y2milestone("Deleting key %1 ('%2')", deleted_key["id"]:"", deleted_key["name"]:"");
	    ret = Pkg::DeleteGPGKey(deleted_key["id"]:"", deleted_key["trusted"]:false) && ret;
	}
    );

    // import the new keys
    foreach(map<string,any> new_key, import_from_file,
	{
	    y2milestone("Importing key %1 from '%2', trusted: %3", new_key["id"]:"", new_key["file"]:"", new_key["trusted"]:false);

	    ret = Pkg::ImportGPGKey(new_key["file"]:"", new_key["trusted"]:false) && ret;
	}
    );

    // all changes are saved, reset them
    deleted_keys = [];
    import_from_file = [];
    modified = false;

    return ret;
}

/**
 * Has been something changed?
 * @return boolean true if something has been changed
 */
global boolean Modified()
{
    return modified;
}

/**
 * Return the current keys.
 * @return list list of known GPG keys ($[ "id" : string, "name" : string, "trusted" : boolean ])
 */
global list<map<string,any> > GetKeys()
{
    return known_keys;
}

/**
 * Delete the key from the package manager
 * @param key_id ID of the key to delete
 * @return boolean true on success
 */
global boolean DeleteKey(string key_id)
{
    if (key_id == nil || key_id == "")
    {
	y2error("Invalid key ID: %1", key_id);
	return false;
    }

    // index of the key
    integer found = nil;
    integer i = 0;

    // copy the key from known keys to the deleted list
    foreach(map<string,any> key, known_keys,
	{
	    if (key["id"]:"" == key_id)
	    {
		deleted_keys = add(deleted_keys, key);
		found = i;
	    }

	    i = i + 1;
	}
    );

    // remove from known keys when found
    if (found != nil)
    {
	known_keys = remove(known_keys, found);
    }

    boolean found_in_imported = false;

    // remove from imported keys (deleting a key scheduled for import)
    import_from_file = filter(map<string,any> new_key, import_from_file,
	{
	    boolean found_key = (new_key["id"]:"" == key_id);
	    found_in_imported = found_in_imported || found_key;

	    return found_key;
	}
    );

    modified = true;

    return (found != nil);
}


/**
 * Import key from a file
 * @param file path to the file
 * @param trusted true if the key is trusted
 * @return map map with the key, nil when import fails (invalid key, not existing file, already imported key...)
 */
global map<string,any> ImportFromFile(string file, boolean trusted)
{
    // check whether the file is valid, copy the file to the tmpdir
    map<string,any> key = Pkg::CheckGPGKeyFile(file);
    y2milestone("File content: %1", key);

    if (key != nil && size(key) > 0)
    {
	// update the trusted flag
	key["trusted"] = trusted;
    }
    else
    {
	Report::Error(sformat(_("File '%1'
doesn't contain a valid GPG key."), file));
	return nil;
    }

    boolean known = false;

    // check whether the key is already known
    foreach(map<string,any> k, known_keys,
	{
	    if (k["id"]:"" == key["id"]:"")
	    {
		known = true;
	    }
	}
    );

    if (known)
    {
	// %1 is key ID (e.g. A84EDAE89C800ACA), %2 is key name (e.g. "SuSE Package Signing Key <build@suse.de>")
	Report::Error(sformat(_("Key '%1'
'%2'
is already known, it cannot be added again."), key["id"]:"", key["name"]:""));
	return nil;
    }

    boolean found_in_deleted = false;
    // check if the key is scheduled for removal
    deleted_keys = filter(map<string,any> deleted_key, deleted_keys,
	{
	    boolean key_found = (deleted_key["id"]:"" == key["id"]:"");
	    found_in_deleted = found_in_deleted || key_found;

	    return !key_found;
	}
    );

    // the key was known, move it to the known list
    if (found_in_deleted)
    {
	known_keys = add(known_keys, key);
	return key;
    }

    // copy the key to the temporary directory (in fact the keys are imported in Write())
    string tmpfile = sformat("%1/tmp_gpg_key.%2", Directory::tmpdir, size(known_keys));
    string command = sformat("/bin/cp -- '%1' '%2'", String::Quote(file), String::Quote(tmpfile));

    y2milestone("Copying the key: %1", command);

    integer out = (integer)SCR::Execute(.target.bash, command);

    if (out != 0)
    {
	Report::Error(_("Cannot copy the key to the temporary directory."));
	return nil;
    }

    // store the import request
    import_from_file = add(import_from_file, $[ "file" : tmpfile, "trusted" : trusted, "id" : key["id"]:"" ]);

    // add the new key to the current config
    known_keys = add(known_keys, key);

    modified = true;

    return key;
}

/* EOF */
}

ACC SHELL 2018