[gnome-shell] location: Add AppAuthorizer class
- From: Zeeshan Ali Khattak <zeeshanak src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] location: Add AppAuthorizer class
- Date: Thu, 18 Feb 2016 15:11:39 +0000 (UTC)
commit 34fc4547647bceff56a0e7a853e14a2ea454c69c
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date: Mon Feb 15 19:45:38 2016 +0000
location: Add AppAuthorizer class
This class will be responsible for authorizing applications that try to
access location information. Since this is mainly targetted for xdg-app
applications, we make use of xdg-app's D-Bus API to store
per-application authorization.
https://bugzilla.gnome.org/show_bug.cgi?id=762119
js/ui/status/location.js | 159 ++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 159 insertions(+), 0 deletions(-)
---
diff --git a/js/ui/status/location.js b/js/ui/status/location.js
index 2dad0b8..ff39432 100644
--- a/js/ui/status/location.js
+++ b/js/ui/status/location.js
@@ -17,6 +17,9 @@ const LOCATION_SCHEMA = 'org.gnome.system.location';
const MAX_ACCURACY_LEVEL = 'max-accuracy-level';
const ENABLED = 'enabled';
+const APP_PERMISSIONS_TABLE = 'desktop';
+const APP_PERMISSIONS_ID = 'geolocation';
+
const GeoclueAccuracyLevel = {
NONE: 0,
COUNTRY: 1,
@@ -26,6 +29,15 @@ const GeoclueAccuracyLevel = {
EXACT: 8
};
+function accuracyLevelToString(accuracyLevel) {
+ for (let key in GeoclueAccuracyLevel) {
+ if (GeoclueAccuracyLevel[key] == accuracyLevel)
+ return key;
+ }
+
+ return 'NONE';
+}
+
var GeoclueIface = '<node> \
<interface name="org.freedesktop.GeoClue2.Manager"> \
<property name="InUse" type="b" access="read"/> \
@@ -50,6 +62,24 @@ var AgentIface = '<node> \
</interface> \
</node>';
+var XdgAppIface = '<node> \
+ <interface name="org.freedesktop.XdgApp.PermissionStore"> \
+ <method name="Lookup"> \
+ <arg name="table" type="s" direction="in"/> \
+ <arg name="id" type="s" direction="in"/> \
+ <arg name="permissions" type="a{sas}" direction="out"/> \
+ <arg name="data" type="v" direction="out"/> \
+ </method> \
+ <method name="Set"> \
+ <arg name="table" type="s" direction="in"/> \
+ <arg name="create" type="b" direction="in"/> \
+ <arg name="id" type="s" direction="in"/> \
+ <arg name="app_permissions" type="a{sas}" direction="in"/> \
+ <arg name="data" type="v" direction="in"/> \
+ </method> \
+ </interface> \
+</node>';
+
const Indicator = new Lang.Class({
Name: 'LocationIndicator',
Extends: PanelMenu.SystemIndicator,
@@ -222,6 +252,135 @@ function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
+const AppAuthorizer = new Lang.Class({
+ Name: 'LocationAppAuthorizer',
+
+ _init: function(desktopId,
+ reqAccuracyLevel,
+ permStoreProxy,
+ maxAccuracyLevel) {
+ this.desktopId = desktopId;
+ this.reqAccuracyLevel = reqAccuracyLevel;
+ this._permStoreProxy = permStoreProxy;
+ this._maxAccuracyLevel = maxAccuracyLevel;
+
+ this._accuracyLevel = GeoclueAccuracyLevel.NONE;
+ this._timesAllowed = 0;
+ },
+
+ authorize: function(onAuthDone) {
+ this._onAuthDone = onAuthDone;
+
+ let appSystem = Shell.AppSystem.get_default();
+ this._app = appSystem.lookup_app(this.desktopId + ".desktop");
+ if (this._app == null || this._permStoreProxy == null) {
+ this._completeAuth();
+
+ return;
+ }
+
+ this._permStoreProxy.LookupRemote(APP_PERMISSIONS_TABLE,
+ APP_PERMISSIONS_ID,
+ Lang.bind(this,
+ this._onPermLookupDone));
+ },
+
+ _onPermLookupDone: function(result, error) {
+ if (error != null) {
+ if (error.domain == Gio.DBusError) {
+ // Likely no xdg-app installed, just authorize the app
+ this._accuracyLevel = this.reqAccuracyLevel;
+ this._permStoreProxy = null;
+ this._completeAuth();
+ } else {
+ // Currently xdg-app throws an error if we lookup for
+ // unknown ID (which would be the case first time this code
+ // runs) so we continue with user authorization as normal
+ // and ID is added to the store if user says "yes".
+ log(error.message);
+ this._permissions = {};
+ this._userAuthorizeApp();
+ }
+
+ return;
+ }
+
+ [this._permissions] = result;
+ let permission = this._permissions[this.desktopId];
+
+ let [levelStr, timeStr] = permission || ['NONE', '0'];
+ this._accuracyLevel = GeoclueAccuracyLevel[levelStr] ||
+ GeoclueAccuracyLevel.NONE;
+ this._timesAllowed = Number(timeStr) || 0;
+
+ if (this._timesAllowed < 3)
+ this._userAuthorizeApp();
+ else
+ this._completeAuth();
+ },
+
+ _userAuthorizeApp: function() {
+ let name = this._app.get_name();
+ let appInfo = this._app.get_app_info();
+ let reason = appInfo.get_string("X-Geoclue-Reason");
+
+ this._showAppAuthDialog(name, reason);
+ },
+
+ _showAppAuthDialog: function(name, reason) {
+ this._dialog = new GeolocationDialog(name,
+ reason,
+ this.reqAccuracyLevel);
+
+ let responseId = this._dialog.connect('response', Lang.bind(this,
+ function(dialog, level) {
+ this._dialog.disconnect(responseId);
+ this._accuracyLevel = level;
+ this._completeAuth();
+ }));
+
+ this._dialog.open();
+ },
+
+ _completeAuth: function() {
+ if (this._accuracyLevel != GeoclueAccuracyLevel.NONE) {
+ this._accuracyLevel = clamp(this._accuracyLevel,
+ 0,
+ this._maxAccuracyLevel);
+ this._timesAllowed++;
+ }
+ this._saveToPermissionStore();
+
+ this._onAuthDone(this._accuracyLevel);
+ },
+
+ _saveToPermissionStore: function() {
+ if (this._permStoreProxy == null)
+ return;
+
+ if (this._accuracyLevel != GeoclueAccuracyLevel.NONE) {
+ let levelStr = accuracyLevelToString(this._accuracyLevel);
+ let dateStr = Math.round(Date.now() / 1000).toString();
+ this._permissions[this.desktopId] = [levelStr,
+ this._timesAllowed.toString(),
+ dateStr];
+ } else {
+ delete this._permissions[this.desktopId];
+ }
+ let data = GLib.Variant.new('av', {});
+
+ this._permStoreProxy.SetRemote(APP_PERMISSIONS_TABLE,
+ true,
+ APP_PERMISSIONS_ID,
+ this._permissions,
+ data,
+ function (result, error) {
+ if (error != null)
+ log(error.message);
+ });
+ },
+});
+
const GeolocationDialog = new Lang.Class({
Name: 'GeolocationDialog',
Extends: ModalDialog.ModalDialog,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]