[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-panel-devel
Subject:    Remote Widgets API
From:       Rob Scheepmaker <r.scheepmaker () student ! utwente ! nl>
Date:       2009-08-30 21:02:00
Message-ID: 200908302302.01148.r.scheepmaker () student ! utwente ! nl
[Download RAW message or body]

Hello,

For the people that are unfortunate enough to are not at Tokamak 3 right now, 
I've got the current remote widgets api attached (I think it's complete but 
I'm not 100% sure, let me know if anything seems missing). We will discuss it 
here, but we don't want to deprive you of commenting on it as well... Let's 
make this api perfect! And if you have any questions, just ask, I'll probably 
be around on IRC most of the time.

Regards,
Rob

["RemoteWidgetApiTokamak.h" (text/x-chdr)]

/**
Overview:
Most of the new api is focussed on plasma shells, to allow them to access remote \
widgets and allow them controll over the security aspects. The one class every shell \
should at least use is AuthorizationManager, which allows shells the type of security \
they want. There are a couple of 'presets' (e.g. allow no remote access at all, \
always do pin pairing for untrusted clients etc.), but you can define custom behavior \
by implementing an AuthorizationInterface and setting that with AuthorizationManager. \
After setting AuthorizationManager up, always call lock(); so plasma plugins can't \
change security stuff themselves. The other class most plasma shells will probably \
want to use is AccessManager, which allows access to remote plasma widgets. The \
reason this is not in Applet like Applet::load is that accessing a remote plasmoid is \
an asynchronous operation (it returns a PlasmoidAccessJob) and so wouldn't be very \
consistent. The AccessManager also allows the shell to be notified of new plasmoids \
that are published through zeroconf, or get a list of plasmoids that are published \
through zeroconf. The way the origin of access attempts is identified is through a \
class called Identity, which handles all message signing/verifying. We basically \
identify any incoming connection by a hash of their public key. AuthorizationManager \
takes care of actually checking if a certain identity has to be allowed or denied \
access to a certain service. I will discuss with Dario about integrating this with \
PolicyKit, which seems like a good idea, but it will probably still be abstracted by \
AuthorizationRule so that won't affect the API much. Besides some minor additions to \
the api in for example service and dataengine, the rest of the work is mostly in \
private classes. Most of it is build on top of Plasma::Service, so for example \
accessing a remote dataengine actually returns a DataEngine subclass that uses a \
                remote published Plasma::Service to fetch updates and what not.
*/

/**
 * @class AccessManager plasma/accessmanager.h <Plasma/AccessManager>
 *
 * @short Allows access to remote Plasma::Service, Plasma::DataEngine and \
                Plasma::Applet classes.
 *
 * This manager provides a way to access a plasmoid that is hosted on another \
                machine. It also
 * provides a mechanism to discover services announced to the network through \
                zeroconf or
 * bluetooth.
 * All access function are asynchronous. The services need to be accessed over the \
                network, and
 * might even have to be authorized by the user of that machine first. All access \
                functions
 * therefore return a job that can be monitored to see when the service is ready for \
                use.
 *
 * @since 4.4?
 */
class PLASMA_EXPORT AccessManager : public QObject
{
    Q_OBJECT

    public:
        /**
         * Singleton pattern accessor.
         */
        static AccessManager *self();

        /**
         * Access a native plasmoid hosted on another machine.
         * @param location the location of the remote plasmoids. Exmples of valid \
                urls:
         * plasma://ip:port/!/resourceName
         * zeroconf://PlasmoidName
         * @returns a job that can be used to track when a remote plasmoid is ready \
                for use, and to
         * obtain the applet when the package is sent over.
         */
        PlasmoidAccessJob *accessPlasmoid(const KUrl &location) const;

        /**
         * @returns a map mapping service names to the plasmoid's metadata.
         */
        QMap<QString, PackageMetadata> remotePlasmoids() const;

    Q_SIGNALS:
        /**
         * fires when a PlasmoidAccessJob is finished.
         */
        void plasmoidAccessFinished(Plasma::PlasmoidAccessJob*);

        /**
         * fires when a new plasmoid is announced on the network.
         */
        void remotePlasmoidAdded(Plasma::PackageMetadata metadata);

        /**
         * fires when an announced plasmoid disappears from the network.
         */
        void remotePlasmoidRemoved(Plasma::PackageMetadata metadata);

    private:
        AccessManager();
        ~AccessManager();

        AccessManagerPrivate * const d;

        Q_PRIVATE_SLOT(d, void slotJobFinished(KJob*))
        Q_PRIVATE_SLOT(d, void slotAddService(DNSSD::RemoteService::Ptr service))
        Q_PRIVATE_SLOT(d, void slotRemoveService(DNSSD::RemoteService::Ptr service))

        friend class AccessManagerPrivate;
        friend class AccessManagerSingleton;
};

/**
 * @class AuthorizationInterface plasma/authorizationinterface.h \
                <Plasma/AuthorizationInterface>
 *
 * @short Allows authorization of access to plasma services.
 *
 * This class is only needed when you create a plasma shell, and none of the presets \
                for 
 * AuthorizationManager matches your use case. When you implement it and register it
 * with the AuthorizationManager class, it allows you to respond to incoming service \
                access
 * attempts. Whenever a message is received that does not match any of the \
                AuthorizationRules,
 * AuthorizationManager creates a new rule matching it, and passes it to the \
                authorize function.
 * Change the rule from Unspecified to something else like Allow or Deny to continue \
                processing the
 * message.
 *
 * @since 4.4?
 */
class PLASMA_EXPORT AuthorizationInterface
{
    public:
        virtual ~AuthorizationInterface();

        /**
         * implement this function to respond to an incoming request that doesn't \
                match any rule.
         * @param rule a new AuthorizationRule matching an incoming operation. Call \
                setRules on this
         * rule to allow/deny the operation.
         */
        virtual void authorize(AuthorizationRule *rule) = 0;

        /**
         * Implement this function to respond to an outgoing connection that needs a \
                password to
         * connect succesfully. As a response to this you'll probably want to show a \
                dialog.
         * @param request a ClientPinRequest where you can call setPin on to set the \
                pin for the
         * outgoing connection.
         */
        virtual void clientPinRequest(ClientPinRequest *request) = 0;

    protected:
        AuthorizationInterface();
};

/**
 * @class AuthorizationManager plasma/authorizationmanager.h <Plasma/AccessManager>
 *
 * @short Allows authorization of access to plasma services.
 *
 * This is the class where every message to or from another machine passes through. 
 * It's responsibilities are:
 * - creating/keeping a public/private key pair for message signing.
 * - testing whether or not the sender is allowed to access the requested resource by \
                testing the
 *   request to a set of rules.
 * - allowing the shell to respond to a remote request that doesn't match any of the 
 *   rules that are in effect.
 * Besides internal use in libplasma, the only moment you'll need to access this \
                class is when you
 * implement a plasma shell. 
 *
 * @since 4.4?
 */
class PLASMA_EXPORT AuthorizationManager : public QObject
{
    Q_OBJECT
    public:
        enum AuthorizationPolicy {
            DenyAllAuthorizationPolicy = 0,  /** < Don't allow any incoming \
                connections */
            PinPairingAuthorizationPolicy = 1, /**< Standard PIN pairing for \
                untrusted connections
*/
            TrustedOnlyAuthorizatonPolicy = 2, /** < Only allow connections from \
                trusted machines */
            CustomAuthorizationPolicy = 3 /** < Specify a custom \
AuthorizationInterface */  };
        
        /**
         * Singleton pattern accessor.
         */
        static AuthorizationManager *self();

        /**
         * Set a policy used for authorizing incoming connections. You can either use \
                one of the
         * included policies, Default is to deny all incoming connections.
         */
        void setAuthorizationPolicy(AuthorizationPolicy policy);
        
        /**
         * Register an implementation of AuthorizationInterface. Use this to make \
                your shell
         * handle authorization requests.
         */
        void setAuthorizationInterface(AuthorizationInterface *interface);

        /**
         * Don't allow any changes to be made to this authorization manager. Always \
                call after
         * setting it up.
         */
        void lock();

    private:
        AuthorizationManager();
        ~AuthorizationManager();

        AuthorizationManagerPrivate *const d;

        Q_PRIVATE_SLOT(d, void loadRules())

        friend class AuthorizationManagerSingleton;
        friend class AuthorizationRule;
        friend class Applet;
        friend class DataEngine;
        friend class GetSource;
        friend class Identity;
        friend class Package;
        friend class PlasmoidServiceJob;
        friend class RemoteService;
        friend class RemoteServiceJob;
        friend class ServiceProvider;
};

/**
 * @class AuthorizationRule plasma/authorizationrule.h <Plasma/AuthorizationRule>
 *
 * @short Defines a rule indicating whether or not a certain service can be accessed \
                by a certain
 * machine.
 *
 * Rules allow you to have control over which computers are allowed to access which
 * services. Everytime a message get's in, AuthorizationManager validates it's \
                sender, and then
 * checks it's list of rules for rules matching the sender and/or the service. If no \
                rules match,
 * or all matching rules have the value Unspecified, AuthorizationManager will create \
                a new rule
 * for this message, and invoke authorize on your shells implementation of \
                AuthorizationInterface.
 * Here, you can change that rule to either allow or deny that request.
 * This class can be used to specify different types of rules:
 * - Rules matching only a user
 * - Rules matching only a service
 * - Rules matching both a service, and a user.
 * A more specific rule always takes precedence over a more global rule: so if for \
                example you have
 * a rule for "myAwesomeService" specifying Deny, and a rule for "myAwesomeService" \
                in combination
 * with "130.42.120.146" as caller specifying Allow, only 130.42.120.146 can access
 * myAwesomeService.
 * By setting the PinRequired flag in setRules in an AuthorizationInterface \
                implementation, you
 * trigger Pin pairing (user will be asked to enter the same password on both \
                machines).
 *
 * @since 4.4?
 */
class PLASMA_EXPORT AuthorizationRule : public QObject
{
    Q_OBJECT
    public:
        ~AuthorizationRule();
        /**
         * Defines this rule's behavior. 
         */
        enum Rule {
            Unspecified = 0,    /**< this rule doesn't specify if the access is \
                allowed or not. */
            Deny = 1,           /**< access for messages matching this rule is \
                denied. */
            Allow = 2,          /**< access for messages matching this rule is \
                allowed. */
            AllUsers = 4,       /**< specify that this rule is valid for all users */
            AllServices = 8,    /**< specify that this rule is valid for all services \
                */
            PinRequired = 16,   /**< specify that the user will need to enter a pin \
at both sides */  DefaultRule = Unspecified
        };
        Q_DECLARE_FLAGS(Rules, Rule)

        /**
         * @returns a friendly and i18n'd description of the current rule, useful for \
                creating a
         * GUI to allow editing rules, or asking permission for an access attempt.
         */
        QString description() const;

        /**
         * @returns whether or not this rule matches a certain message.
         */
        bool matches(const QString &serviceName, const Identity &identity) const;

        /**
         * @param rules the flags describing this rule.
         */
        void setRules(Rules rules);

        /**
         * @returns the flags describing this rule.
         */
        Rules rules();

        /**
         * @param pin set pin for pin pairing. You'll need to call this bevore \
                setting the rule.
         */
        void setPin(const QString &pin);

        /**
         * @returns the pin for pin pairing.
         */
        QString pin() const;

        /**
         * @returns the identity of the caller.
         */
        Identity identity() const;

        /**
         * @returns the name of the service this rule applies to.
         */
        QString serviceName() const;

    Q_SIGNALS:
        void changed(AuthorizationRule *rule);

    private:
        AuthorizationRule(const QString &serviceName, Identity identity);

        AuthorizationRulePrivate * const d;

        friend class AuthorizationManager;
        friend class AuthorizationManagerPrivate;
        friend class ServiceProvider;
        friend class GetSource;
        friend class PlasmoidServiceJob;
};

/**
 * @class ClientPinRequest plasma/clientpinrequest.h <Plasma/ClientPinRequest>
 *
 * describes an outgoing connection.
 *
 * @since 4.4?
 */
class PLASMA_EXPORT ClientPinRequest : public QObject
{
    Q_OBJECT
    public:
        /**
         * @returns nice i18n'ed description of this outgoing connection.
         */
        QString description() const;

        /**
         * @param pin set a pin for pin pairing.
         */
        void setPin(const QString &pin);

        /**
         * @returns the pin for pin pairing.
         */
        QString pin() const;

    Q_SIGNALS:
        /**
         * Emitted when a pin is set.
         */
        void changed(Plasma::ClientPinRequest*);

    private:
        ClientPinRequest(RemoteService *service);
        ~ClientPinRequest();
        
        ClientPinRequestPrivate * const d;

        friend class RemoteService;

};

/**
 * @class PlasmoidAccessJob plasma/plasmoidaccessjob.h <Plasma/PlasmoidAccessJob>
 *
 * @short This class is used for asynchronously accessing an applet published on a \
                remote system.
 * After calling AccessManager::accessPlasmoid, monitor this job to track when the \
                remote applet
 * is ready to be used, and to obtain the service when finished.
 */
class PLASMA_EXPORT PlasmoidAccessJob : public KJob
{
    Q_OBJECT

public:
    ~PlasmoidAccessJob();
    
    Applet *applet() const;

protected:
    /**
     * Default constructor
     *
     * @arg location the location of the service
     * @arg parent the parent object for this service
     */
    PlasmoidAccessJob(const KUrl &location, QObject *parent = 0);

    void start();

private:
    Q_PRIVATE_SLOT(d, void slotPackageDownloaded(Plasma::ServiceJob*))
    Q_PRIVATE_SLOT(d, void slotStart())
    Q_PRIVATE_SLOT(d, void slotServiceReady(Plasma::Service*))
    Q_PRIVATE_SLOT(d, void slotTimeout())

    PlasmoidAccessJobPrivate * const d;
    
    friend class AccessManager;
    friend class AccessManagerPrivate;
    friend class PlasmoidAccessJobPrivate;
};

/**
 * @class Identity plasma/identity.h <Plasma/Identity>
 *
 * This class encapsules someone's identity.
 * It contains a unique id that identifies the machine an incoming connection is \
                coming from, it's
 * name (which is not necesarily unique and/or trusted), a public key used to \
                validate messages
 * coming from the machine with this identity, and in the future the possibility to \
                determine
 * whether or not this identity can be trusted based on mechanisms different then pin \
                pairing, e.g.
 * a signature of the key that can be verified by a gpg trusted key.
 */
class Identity
{
public:
    /**
     * Default constructor.
     */
    Identity();

    /**
     * Copy constructor.
     */
    Identity(const Identity &other);
    
    ~Identity();
    
    Identity &operator=(const Identity &other);

    /**
     * Create a new identity with a new set of random public/private keys.
     */
    static Identity createIdentity(const QString &name);
    
    /**
     * @return whether or not this identity can be trusted based on e.g. having the \
                key signed with
     * a trusted GPG key (not yet implemented) or having the key in a designated \
                folder on disk.
     * If this function returns false, your shell should always at least instatiate
     * pin pairing before allowing a connection from an untrusted source
     * (AuthorizationRule::PinRequired flag should be set on the rule with setRules).
     * TODO: should indicate a level of trust instead of just true/false
     */
    bool isTrusted() const;

    /**
     * @return whether or not this is a null identity.
     */
    bool isNull() const;

    /**
     * @return the name of this identity. There's however no guarantee that if the \
                name returns e.g.
     * "Santa Claus", this message is actually from Mr. Claus, except if isTrusted is \
                true.
     */
    QString name() const;

    /**
     * @return an id to identify this identity. I use a Hash of the public key as ID. \
                This way we
     * don't have to send the complete public key with every message.
     */
    QString id() const;

    /**
     * @return wheter or not @p signature is correct for @p message.
     */
    bool isValidSignature(const QByteArray &signature, const QByteArray &message);

    /**
     * @return whether or not this identity can be used for signing a message \
                (whether or not it
     * includes a public key)
     */
    bool canSign() const;

    /**
     * @return the signature for the message.
     */
    QByteArray signMessage(const QByteArray &message);

    /**
     * @return a Identity stripped from any private key, so you can be sure it is \
                save to send to
     * somebody.
     */
    Identity toPublicIdentity() const;
    
    friend QDataStream &operator<<(QDataStream &, const Identity &);
    friend QDataStream &operator>>(QDataStream &, Identity &);

private:
    Identity(const QString &id, const QString &name, const QString &key,
             bool privateKey = false);
             
    IdentityPrivate *const d;
    
    friend class AuthorizationManagerPrivate;
    friend class IdentityPrivate;
};

/**
 * Streaming operators for sending/storing identities.
 */
QDataStream &operator<<(QDataStream &, const Identity &);
QDataStream &operator>>(QDataStream &, Identity &);

Additions to Plasma::DataEngine:
  public:

        /**
         * @param methods ways to announce this engine on the network.
         */
        void publish(const QString &name, PublicationMethods methods = None);

        /**
         * remove this engine from the network.
         */
        void unPublish();

        /**
         * @return whether or not this engine is published.
         */
        bool isPublished() const;

Additions to Plasma::Service
  public:
	/**
	* Used to access a service from an url. Always check for the signal serviceReady() \
                that fires
	* when this service is actually ready for use.
	*/
	static Service *access(const KUrl &url, QObject *parent = 0);
	
       /**
	* Publish this service on the network.
	* @param name The name under which this service get's published.
	* @param methods The methods we use for publication.
	* @param metadata A package metadata object which will be used to publish metadata \
                in
	* zeroconf's textdata.
	*/
	void publish(const QString &name, PublicationMethods methods = None,
		    PackageMetadata metadata = PackageMetadata());

	void unPublish();

	bool isPublished() const;
	
  Q_SIGNALS:
	/**
	* Emitted when this service is ready for use
	*/
	void serviceReady(Plasma::Service *service);
	
Additions to PackageMetadata
  public:
	QString remoteLocation() const;
	void setRemoteLocation(const QString &);
    
Additions to Applet
  public:
        void publish(Plasma::PublicationMethods method);

        void unPublish();

        bool isPublished() const;



_______________________________________________
Plasma-devel mailing list
Plasma-devel@kde.org
https://mail.kde.org/mailman/listinfo/plasma-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic