mirror of
https://github.com/edu4rdshl/gnome-shell.git
synced 2026-07-17 23:24:51 +00:00
Merge branch 'homed-secure-lock' into 'main'
Draft: Deeper integration w/ homed secure lock See merge request GNOME/gnome-shell!3279
This commit is contained in:
commit
600d728d7d
9 changed files with 154 additions and 33 deletions
|
|
@ -20,6 +20,10 @@
|
|||
<method name="ListSessions">
|
||||
<arg name="sessions" type="a(susso)" direction="out"/>
|
||||
</method>
|
||||
<method name="GetUserByPID">
|
||||
<arg type="u" name="pid" direction="in"/>
|
||||
<arg type="o" name="object_path" direction="out"/>
|
||||
</method>
|
||||
<method name="CanRebootToBootLoaderMenu">
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
|
|
|
|||
|
|
@ -2,5 +2,7 @@
|
|||
<interface name="org.freedesktop.login1.User">
|
||||
<property name="Display" type="(so)" access="read"/>
|
||||
<property name="Sessions" type="a(so)" access="read"/>
|
||||
<property name="CanSecureLock" type="b" access="read"/>
|
||||
<method name="SecureLock" />
|
||||
</interface>
|
||||
</node>
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ export const AuthPrompt = GObject.registerClass({
|
|||
'next': {},
|
||||
'prompted': {},
|
||||
'reset': {param_types: [GObject.TYPE_UINT]},
|
||||
'verified': {},
|
||||
},
|
||||
}, class AuthPrompt extends St.BoxLayout {
|
||||
_init(gdmClient, mode) {
|
||||
|
|
@ -404,6 +405,7 @@ export const AuthPrompt = GObject.registerClass({
|
|||
this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED;
|
||||
this.cancelButton.reactive = false;
|
||||
this.cancelButton.can_focus = false;
|
||||
this.emit('verified');
|
||||
}
|
||||
|
||||
_onReset() {
|
||||
|
|
|
|||
|
|
@ -97,13 +97,12 @@ class LoginManagerSystemd extends Signals.EventEmitter {
|
|||
this._proxy = new SystemdLoginManager(Gio.DBus.system,
|
||||
'org.freedesktop.login1',
|
||||
'/org/freedesktop/login1');
|
||||
this._userProxy = new SystemdLoginUser(Gio.DBus.system,
|
||||
'org.freedesktop.login1',
|
||||
'/org/freedesktop/login1/user/self');
|
||||
this._proxy.connectSignal('PrepareForSleep',
|
||||
this._prepareForSleep.bind(this));
|
||||
this._proxy.connectSignal('SessionRemoved',
|
||||
this._sessionRemoved.bind(this));
|
||||
|
||||
this._userProxy = this._initUserProxy();
|
||||
}
|
||||
|
||||
async getCurrentSessionProxy() {
|
||||
|
|
@ -113,19 +112,20 @@ class LoginManagerSystemd extends Signals.EventEmitter {
|
|||
let sessionId = GLib.getenv('XDG_SESSION_ID');
|
||||
if (!sessionId) {
|
||||
log('Unset XDG_SESSION_ID, getCurrentSessionProxy() called outside a user session. Asking logind directly.');
|
||||
let [session, objectPath] = this._userProxy.Display;
|
||||
let userProxy = await this._userProxy;
|
||||
let [session, objectPath] = userProxy.Display;
|
||||
if (session) {
|
||||
log(`Will monitor session ${session}`);
|
||||
sessionId = session;
|
||||
} else {
|
||||
log('Failed to find "Display" session; are we the greeter?');
|
||||
|
||||
for ([session, objectPath] of this._userProxy.Sessions) {
|
||||
for ([session, objectPath] of userProxy.Sessions) {
|
||||
let sessionProxy = new SystemdLoginSession(Gio.DBus.system,
|
||||
'org.freedesktop.login1',
|
||||
objectPath);
|
||||
log(`Considering ${session}, class=${sessionProxy.Class}`);
|
||||
if (sessionProxy.Class === 'greeter') {
|
||||
if (sessionProxy.Class === 'greeter' || sessionProxy.Class === "lock-screen") {
|
||||
log(`Yes, will monitor session ${session}`);
|
||||
sessionId = session;
|
||||
break;
|
||||
|
|
@ -217,6 +217,27 @@ class LoginManagerSystemd extends Signals.EventEmitter {
|
|||
_sessionRemoved(proxy, sender, [sessionId]) {
|
||||
this.emit('session-removed', sessionId);
|
||||
}
|
||||
|
||||
async _initUserProxy() {
|
||||
let [objectPath] = await this._proxy.GetUserByPIDAsync(0)
|
||||
|
||||
let proxy = new SystemdLoginUser(Gio.DBus.system,
|
||||
'org.freedesktop.login1',
|
||||
objectPath);
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
async canSecureLock() {
|
||||
const proxy = await this._userProxy;
|
||||
return proxy.CanSecureLock;
|
||||
}
|
||||
|
||||
async secureLock() {
|
||||
const proxy = await this._userProxy;
|
||||
if (proxy.CanSecureLock)
|
||||
await proxy.SecureLockAsync(0);
|
||||
}
|
||||
}
|
||||
|
||||
class LoginManagerDummy extends Signals.EventEmitter {
|
||||
|
|
@ -261,4 +282,11 @@ class LoginManagerDummy extends Signals.EventEmitter {
|
|||
async inhibit() {
|
||||
return null;
|
||||
}
|
||||
|
||||
async canSecureLock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
async secureLock() {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const ALWAYS_SHOW_LOG_OUT_KEY = 'always-show-log-out';
|
|||
const POWER_OFF_ACTION_ID = 'power-off';
|
||||
const RESTART_ACTION_ID = 'restart';
|
||||
const LOCK_SCREEN_ACTION_ID = 'lock-screen';
|
||||
const SECURE_LOCK_ACTION_ID = 'secure-lock'
|
||||
const LOGOUT_ACTION_ID = 'logout';
|
||||
const SUSPEND_ACTION_ID = 'suspend';
|
||||
const SWITCH_USER_ACTION_ID = 'switch-user';
|
||||
|
|
@ -57,6 +58,10 @@ const SystemActions = GObject.registerClass({
|
|||
'can-lock-screen', 'can-lock-screen', 'can-lock-screen',
|
||||
GObject.ParamFlags.READABLE,
|
||||
false),
|
||||
'can-secure-lock': GObject.ParamSpec.boolean(
|
||||
'can-secure-lock', 'can-secure-lock', 'can-secure-lock',
|
||||
GObject.ParamFlags.READABLE,
|
||||
false),
|
||||
'can-switch-user': GObject.ParamSpec.boolean(
|
||||
'can-switch-user', 'can-switch-user', 'can-switch-user',
|
||||
GObject.ParamFlags.READABLE,
|
||||
|
|
@ -110,6 +115,14 @@ const SystemActions = GObject.registerClass({
|
|||
keywords: tokenizeKeywords(_('lock screen')),
|
||||
available: false,
|
||||
});
|
||||
this._actions.set(SECURE_LOCK_ACTION_ID, {
|
||||
// Translators: The name of the secure lock action in search
|
||||
name: C_('search-result', 'Secure Lock'),
|
||||
iconName: 'security-high-symbolic',
|
||||
// Translators: A list of keywords that match the secure lock action, separated by semicolons
|
||||
keywords: tokenizeKeywords(_('encrypt;lock down;lockdown')),
|
||||
available: false,
|
||||
});
|
||||
this._actions.set(LOGOUT_ACTION_ID, {
|
||||
// Translators: The name of the logout action in search
|
||||
name: C_('search-result', 'Log Out'),
|
||||
|
|
@ -176,8 +189,10 @@ const SystemActions = GObject.registerClass({
|
|||
global.settings.connect(`changed::${ALWAYS_SHOW_LOG_OUT_KEY}`,
|
||||
() => this._updateLogout());
|
||||
|
||||
this._lockdownSettings.connect(`changed::${DISABLE_LOCK_SCREEN_KEY}`,
|
||||
() => this._updateLockScreen());
|
||||
this._lockdownSettings.connect(`changed::${DISABLE_LOCK_SCREEN_KEY}`, () => {
|
||||
this._updateLockScreen();
|
||||
this._updateSecureLock();
|
||||
});
|
||||
|
||||
this._lockdownSettings.connect(`changed::${DISABLE_LOG_OUT_KEY}`,
|
||||
() => this._updateHaveShutdown());
|
||||
|
|
@ -215,6 +230,10 @@ const SystemActions = GObject.registerClass({
|
|||
return this._actions.get(LOCK_SCREEN_ACTION_ID).available;
|
||||
}
|
||||
|
||||
get canSecureLock() {
|
||||
return this._actions.get(SECURE_LOCK_ACTION_ID).available;
|
||||
}
|
||||
|
||||
get canSwitchUser() {
|
||||
return this._actions.get(SWITCH_USER_ACTION_ID).available;
|
||||
}
|
||||
|
|
@ -271,6 +290,9 @@ const SystemActions = GObject.registerClass({
|
|||
// latter, so their value may be outdated; force an update now
|
||||
this._updateHaveShutdown();
|
||||
this._updateHaveSuspend();
|
||||
|
||||
// CanSecureLock changes w/o notification in logind
|
||||
this._updateSecureLock();
|
||||
}
|
||||
|
||||
getMatchingActions(terms) {
|
||||
|
|
@ -311,6 +333,9 @@ const SystemActions = GObject.registerClass({
|
|||
case LOCK_SCREEN_ACTION_ID:
|
||||
this.activateLockScreen();
|
||||
break;
|
||||
case SECURE_LOCK_ACTION_ID:
|
||||
this.activateSecureLock();
|
||||
break;
|
||||
case LOGOUT_ACTION_ID:
|
||||
this.activateLogout();
|
||||
break;
|
||||
|
|
@ -330,12 +355,21 @@ const SystemActions = GObject.registerClass({
|
|||
}
|
||||
|
||||
_updateLockScreen() {
|
||||
let showLock = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
|
||||
let allowLockScreen = !this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY);
|
||||
this._actions.get(LOCK_SCREEN_ACTION_ID).available = showLock && allowLockScreen && LoginManager.canLock();
|
||||
let showLock = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter &&
|
||||
!this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY);
|
||||
let canLock = LoginManager.canLock();
|
||||
this._actions.get(LOCK_SCREEN_ACTION_ID).available = showLock && canLock;
|
||||
this.notify('can-lock-screen');
|
||||
}
|
||||
|
||||
async _updateSecureLock() {
|
||||
let showLock = !Main.sessionMode.isGreeter &&
|
||||
!this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY);
|
||||
let canSecureLock = await this._loginManager.canSecureLock();
|
||||
this._actions.get(SECURE_LOCK_ACTION_ID).available = showLock && canSecureLock;
|
||||
this.notify('can-secure-lock');
|
||||
}
|
||||
|
||||
async _updateHaveShutdown() {
|
||||
try {
|
||||
const [canShutdown] = await this._session.CanShutdownAsync();
|
||||
|
|
@ -423,6 +457,13 @@ const SystemActions = GObject.registerClass({
|
|||
Main.screenShield.lock(true);
|
||||
}
|
||||
|
||||
activateSecureLock() {
|
||||
if (!this._actions.get(SECURE_LOCK_ACTION_ID).available)
|
||||
throw new Error('The secure-lock action is not available!');
|
||||
|
||||
this._loginManager.secureLock();
|
||||
}
|
||||
|
||||
activateSwitchUser() {
|
||||
if (!this._actions.get(SWITCH_USER_ACTION_ID).available)
|
||||
throw new Error('The switch-user action is not available!');
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ export class ScreenShield extends Signals.EventEmitter {
|
|||
|
||||
_activateDialog() {
|
||||
if (this._isLocked) {
|
||||
this._ensureUnlockDialog(true /* allowCancel */);
|
||||
this._ensureUnlockDialog();
|
||||
this._dialog.activate();
|
||||
} else {
|
||||
this.deactivate(true /* animate */);
|
||||
|
|
@ -357,7 +357,8 @@ export class ScreenShield extends Signals.EventEmitter {
|
|||
this.actor.show();
|
||||
this._isGreeter = Main.sessionMode.isGreeter;
|
||||
this._isLocked = true;
|
||||
this._ensureUnlockDialog(true);
|
||||
this._lockScreenState = MessageTray.State.SHOWN;
|
||||
this._ensureUnlockDialog();
|
||||
}
|
||||
|
||||
_hideLockScreenComplete() {
|
||||
|
|
@ -416,7 +417,7 @@ export class ScreenShield extends Signals.EventEmitter {
|
|||
this._showPointer();
|
||||
}
|
||||
|
||||
_ensureUnlockDialog(allowCancel) {
|
||||
_ensureUnlockDialog() {
|
||||
if (!this._dialog) {
|
||||
let constructor = Main.sessionMode.unlockDialog;
|
||||
if (!constructor) {
|
||||
|
|
@ -440,7 +441,6 @@ export class ScreenShield extends Signals.EventEmitter {
|
|||
'wake-up-screen', this._wakeUpScreen.bind(this));
|
||||
}
|
||||
|
||||
this._dialog.allowCancel = allowCancel;
|
||||
this._dialog.grab_key_focus();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -605,7 +605,7 @@ export class ScreenShield extends Signals.EventEmitter {
|
|||
if (this._activationTime === 0)
|
||||
this._activationTime = GLib.get_monotonic_time();
|
||||
|
||||
if (!this._ensureUnlockDialog(true))
|
||||
if (!this._ensureUnlockDialog())
|
||||
return;
|
||||
|
||||
this.actor.show();
|
||||
|
|
@ -620,6 +620,7 @@ export class ScreenShield extends Signals.EventEmitter {
|
|||
animateLockScreen: animate,
|
||||
fadeToBlack: true,
|
||||
});
|
||||
|
||||
// On wayland, a crash brings down the entire session, so we don't
|
||||
// need to defend against being restarted unlocked
|
||||
if (!Meta.is_wayland_compositor())
|
||||
|
|
|
|||
|
|
@ -78,6 +78,19 @@ const _modes = {
|
|||
panelStyle: 'unlock-screen',
|
||||
},
|
||||
|
||||
'lock-screen': {
|
||||
isGreeter: true,
|
||||
isPrimary: true,
|
||||
unlockDialog: UnlockDialog,
|
||||
components: ['polkitAgent'],
|
||||
panel: {
|
||||
left: [],
|
||||
center: [],
|
||||
right: ['dwellClick', 'a11y', 'keyboard', 'quickSettings'],
|
||||
},
|
||||
panelStyle: 'unlock-screen',
|
||||
},
|
||||
|
||||
'user': {
|
||||
hasOverview: true,
|
||||
showCalendarEvents: true,
|
||||
|
|
|
|||
|
|
@ -192,6 +192,11 @@ class ShutdownItem extends QuickSettingsItem {
|
|||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this._addSystemAction(_('Secure Lock'), 'can-secure-lock', () => {
|
||||
this._systemActions.activateSecureLock();
|
||||
Main.panel.closeQuickSettings();
|
||||
});
|
||||
|
||||
this._addSystemAction(_('Log Out…'), 'can-logout', () => {
|
||||
this._systemActions.activateLogout();
|
||||
Main.panel.closeQuickSettings();
|
||||
|
|
|
|||
|
|
@ -535,6 +535,11 @@ export const UnlockDialog = GObject.registerClass({
|
|||
this.add_action(tapAction);
|
||||
|
||||
// Background
|
||||
if (!Main.sessionMode.isGreeter) {
|
||||
// We don't currently support storing a background picture for
|
||||
// user accounts, so for now the secure lock screen will just have
|
||||
// a blank background.
|
||||
|
||||
this._backgroundGroup = new Clutter.Actor();
|
||||
this.add_child(this._backgroundGroup);
|
||||
|
||||
|
|
@ -547,9 +552,21 @@ export const UnlockDialog = GObject.registerClass({
|
|||
this._updateBackgrounds();
|
||||
Main.layoutManager.connectObject('monitors-changed',
|
||||
this._updateBackgrounds.bind(this), this);
|
||||
}
|
||||
|
||||
this._userManager = AccountsService.UserManager.get_default();
|
||||
if (!Main.sessionMode.isGreeter) {
|
||||
this._userName = GLib.get_user_name();
|
||||
} else {
|
||||
this._userName = GLib.getenv('GDM_LOCK_SCREEN_USER');
|
||||
if (!this._userName) {
|
||||
// In the secure lock screen, this is a hard error. Fail-whale
|
||||
const error = new GLib.Error(
|
||||
Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED,
|
||||
'Could not get user for GDM lock screen');
|
||||
global.context.terminate_with_error(error);
|
||||
}
|
||||
}
|
||||
this._user = this._userManager.get_user(this._userName);
|
||||
|
||||
// Authentication & Clock stack
|
||||
|
|
@ -565,8 +582,6 @@ export const UnlockDialog = GObject.registerClass({
|
|||
this._stack.add_child(this._clock);
|
||||
this._showClock();
|
||||
|
||||
this.allowCancel = false;
|
||||
|
||||
Main.ctrlAltTabManager.addGroup(this, _('Unlock Window'), 'dialog-password-symbolic');
|
||||
|
||||
// Notifications
|
||||
|
|
@ -706,6 +721,7 @@ export const UnlockDialog = GObject.registerClass({
|
|||
this._authPrompt.connect('failed', this._fail.bind(this));
|
||||
this._authPrompt.connect('cancelled', this._fail.bind(this));
|
||||
this._authPrompt.connect('reset', this._onReset.bind(this));
|
||||
this._authPrompt.connect('verified', this._onVerified.bind(this));
|
||||
this._promptBox.add_child(this._authPrompt);
|
||||
}
|
||||
|
||||
|
|
@ -802,8 +818,16 @@ export const UnlockDialog = GObject.registerClass({
|
|||
this._authPrompt.begin({userName});
|
||||
}
|
||||
|
||||
_onVerified() {
|
||||
// Make sure we don't get stuck at the successfully authenticated
|
||||
// prompt, when we're running as the secure lock screen in GDM and
|
||||
// the user immediately re-triggers a secure-lock
|
||||
if (Main.sessionMode.isGreeter)
|
||||
this._showClock();
|
||||
}
|
||||
|
||||
_escape() {
|
||||
if (this._authPrompt && this.allowCancel)
|
||||
if (this._authPrompt && !Main.sessionMode.isGreeter)
|
||||
this._authPrompt.cancel();
|
||||
}
|
||||
|
||||
|
|
@ -862,10 +886,11 @@ export const UnlockDialog = GObject.registerClass({
|
|||
}
|
||||
|
||||
_updateUserSwitchVisibility() {
|
||||
this._otherUserButton.visible = this._userManager.can_switch() &&
|
||||
this._userManager.has_multiple_users &&
|
||||
this._screenSaverSettings.get_boolean('user-switch-enabled') &&
|
||||
let needed = this._userManager.can_switch() &&
|
||||
this._userManager.has_multiple_users;
|
||||
let enabled = this._screenSaverSettings.get_boolean('user-switch-enabled') &&
|
||||
!this._lockdownSettings.get_boolean('disable-user-switching');
|
||||
this._otherUserButton.visible = needed && (enabled || Main.sessionMode.isGreeter);
|
||||
}
|
||||
|
||||
cancel() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue