Advertisement
Guest User

Untitled

a guest
Jul 25th, 2020
312
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
  2. /* exported AuthPrompt */
  3.  
  4. const { Clutter, GObject, Pango, Shell, St } = imports.gi;
  5.  
  6. const Animation = imports.ui.animation;
  7. const Batch = imports.gdm.batch;
  8. const GdmUtil = imports.gdm.util;
  9. const Util = imports.misc.util;
  10. const Params = imports.misc.params;
  11. const ShellEntry = imports.ui.shellEntry;
  12. const UserWidget = imports.ui.userWidget;
  13.  
  14. var DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
  15. var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1000;
  16. var DEFAULT_BUTTON_WELL_ANIMATION_TIME = 300;
  17.  
  18. var MESSAGE_FADE_OUT_ANIMATION_TIME = 500;
  19.  
  20. var AuthPromptMode = {
  21.     UNLOCK_ONLY: 0,
  22.     UNLOCK_OR_LOG_IN: 1,
  23. };
  24.  
  25. var AuthPromptStatus = {
  26.     NOT_VERIFYING: 0,
  27.     VERIFYING: 1,
  28.     VERIFICATION_FAILED: 2,
  29.     VERIFICATION_SUCCEEDED: 3,
  30. };
  31.  
  32. var BeginRequestType = {
  33.     PROVIDE_USERNAME: 0,
  34.     DONT_PROVIDE_USERNAME: 1,
  35. };
  36.  
  37. var AuthPrompt = GObject.registerClass({
  38.     Signals: {
  39.         'cancelled': {},
  40.         'failed': {},
  41.         'next': {},
  42.         'prompted': {},
  43.         'reset': { param_types: [GObject.TYPE_UINT] },
  44.     },
  45. }, class AuthPrompt extends St.BoxLayout {
  46.     _init(gdmClient, mode) {
  47.         super._init({
  48.             style_class: 'login-dialog-prompt-layout',
  49.             vertical: true,
  50.             x_expand: true,
  51.             x_align: Clutter.ActorAlign.CENTER,
  52.         });
  53.  
  54.         this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
  55.  
  56.         this._gdmClient = gdmClient;
  57.         this._mode = mode;
  58.         this._defaultButtonWellActor = null;
  59.  
  60.         let reauthenticationOnly;
  61.         if (this._mode == AuthPromptMode.UNLOCK_ONLY)
  62.             reauthenticationOnly = true;
  63.         else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN)
  64.             reauthenticationOnly = false;
  65.  
  66.         this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly });
  67.  
  68.         this._userVerifier.connect('ask-question', this._onAskQuestion.bind(this));
  69.         this._userVerifier.connect('show-message', this._onShowMessage.bind(this));
  70.         this._userVerifier.connect('verification-failed', this._onVerificationFailed.bind(this));
  71.         this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this));
  72.         this._userVerifier.connect('reset', this._onReset.bind(this));
  73.         this._userVerifier.connect('smartcard-status-changed', this._onSmartcardStatusChanged.bind(this));
  74.         this._userVerifier.connect('ovirt-user-authenticated', this._onOVirtUserAuthenticated.bind(this));
  75.         this.smartcardDetected = this._userVerifier.smartcardDetected;
  76.  
  77.         this.connect('destroy', this._onDestroy.bind(this));
  78.  
  79.         this._userWell = new St.Bin({
  80.             x_expand: true,
  81.             y_expand: true,
  82.         });
  83.         this.add_child(this._userWell);
  84.  
  85.         this._hasCancelButton = this._mode === AuthPromptMode.UNLOCK_OR_LOG_IN;
  86.  
  87.         this._initEntryRow();
  88.  
  89.         let capsLockPlaceholder = new St.Label();
  90.         this.add_child(capsLockPlaceholder);
  91.  
  92.         this._capsLockWarningLabel = new ShellEntry.CapsLockWarning({
  93.             x_expand: true,
  94.             x_align: Clutter.ActorAlign.CENTER,
  95.         });
  96.         this.add_child(this._capsLockWarningLabel);
  97.  
  98.         this._capsLockWarningLabel.bind_property('visible',
  99.             capsLockPlaceholder, 'visible',
  100.             GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN);
  101.  
  102.         this._message = new St.Label({
  103.             opacity: 0,
  104.             styleClass: 'login-dialog-message',
  105.             y_expand: true,
  106.             x_expand: true,
  107.             y_align: Clutter.ActorAlign.START,
  108.             x_align: Clutter.ActorAlign.CENTER,
  109.         });
  110.         this._message.clutter_text.line_wrap = true;
  111.         this._message.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
  112.         this.add_child(this._message);
  113.     }
  114.  
  115.     _onDestroy() {
  116.         this._userVerifier.destroy();
  117.         this._userVerifier = null;
  118.     }
  119.  
  120.     vfunc_key_press_event(keyPressEvent) {
  121.         if (keyPressEvent.keyval == Clutter.KEY_Escape)
  122.             this.cancel();
  123.         return super.vfunc_key_press_event(keyPressEvent);
  124.     }
  125.  
  126.     _initEntryRow() {
  127.         this._mainBox = new St.BoxLayout({
  128.             style_class: 'login-dialog-button-box',
  129.             vertical: false,
  130.         });
  131.         this.add_child(this._mainBox);
  132.  
  133.         this.cancelButton = new St.Button({
  134.             style_class: 'modal-dialog-button button cancel-button',
  135.             accessible_name: _('Cancel'),
  136.             button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
  137.             reactive: this._hasCancelButton,
  138.             can_focus: this._hasCancelButton,
  139.             x_align: Clutter.ActorAlign.START,
  140.             y_align: Clutter.ActorAlign.CENTER,
  141.             child: new St.Icon({ icon_name: 'go-previous-symbolic' }),
  142.         });
  143.         if (this._hasCancelButton)
  144.             this.cancelButton.connect('clicked', () => this.cancel());
  145.         else
  146.             this.cancelButton.opacity = 0;
  147.         this._mainBox.add_child(this.cancelButton);
  148.  
  149.         let entryParams = {
  150.             style_class: 'login-dialog-prompt-entry',
  151.             can_focus: true,
  152.             x_expand: true,
  153.         };
  154.  
  155.         this._entry = null;
  156.  
  157.         this._textEntry = new St.Entry(entryParams);
  158.         ShellEntry.addContextMenu(this._textEntry, { actionMode: Shell.ActionMode.NONE });
  159.  
  160.         this._passwordEntry = new St.PasswordEntry(entryParams);
  161.         ShellEntry.addContextMenu(this._passwordEntry, { actionMode: Shell.ActionMode.NONE });
  162.  
  163.         this._entry = this._passwordEntry;
  164.         this._mainBox.add_child(this._entry);
  165.         this._entry.grab_key_focus();
  166.  
  167.         [this._textEntry, this._passwordEntry].forEach(entry => {
  168.             entry.clutter_text.connect('text-changed', () => {
  169.                 if (!this._userVerifier.hasPendingMessages)
  170.                     this._fadeOutMessage();
  171.             });
  172.  
  173.             entry.clutter_text.connect('activate', () => {
  174.                 let shouldSpin = entry === this._passwordEntry;
  175.                 if (entry.reactive)
  176.                     this._activateNext(shouldSpin);
  177.             });
  178.         });
  179.  
  180.         this._defaultButtonWell = new St.Widget({
  181.             layout_manager: new Clutter.BinLayout(),
  182.             x_align: Clutter.ActorAlign.END,
  183.             y_align: Clutter.ActorAlign.CENTER,
  184.         });
  185.         this._defaultButtonWell.add_constraint(new Clutter.BindConstraint({
  186.             source: this.cancelButton,
  187.             coordinate: Clutter.BindCoordinate.SIZE,
  188.         }));
  189.         this._mainBox.add_child(this._defaultButtonWell);
  190.  
  191.         this._spinner = new Animation.Spinner(DEFAULT_BUTTON_WELL_ICON_SIZE);
  192.         this._defaultButtonWell.add_child(this._spinner);
  193.     }
  194.  
  195.     _activateNext(shouldSpin) {
  196.         this.updateSensitivity(false);
  197.  
  198.         if (shouldSpin)
  199.             this.startSpinning();
  200.  
  201.         if (this._queryingService)
  202.             this._userVerifier.answerQuery(this._queryingService, this._entry.text);
  203.         else
  204.             this._preemptiveAnswer = this._entry.text;
  205.  
  206.         this.emit('next');
  207.     }
  208.  
  209.     _updateEntry(secret) {
  210.         if (secret && this._entry !== this._passwordEntry) {
  211.             this._mainBox.replace_child(this._entry, this._passwordEntry);
  212.             this._entry = this._passwordEntry;
  213.         } else if (!secret && this._entry !== this._textEntry) {
  214.             this._mainBox.replace_child(this._entry, this._textEntry);
  215.             this._entry = this._textEntry;
  216.         }
  217.         this._capsLockWarningLabel.visible = secret;
  218.     }
  219.  
  220.     _onAskQuestion(verifier, serviceName, question, secret) {
  221.         if (this._queryingService)
  222.             this.clear();
  223.  
  224.         this._queryingService = serviceName;
  225.         if (this._preemptiveAnswer) {
  226.             this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer);
  227.             this._preemptiveAnswer = null;
  228.             return;
  229.         }
  230.  
  231.         this._updateEntry(secret);
  232.  
  233.         // Hack: The question string comes directly from PAM, if it's "Password:"
  234.         // we replace it with our own to allow localization, if it's something
  235.         // else we remove the last colon and any trailing or leading spaces.
  236.         if (question === 'Password:' || question === 'Password: ')
  237.             this.setQuestion(_('Password'));
  238.         else
  239.             this.setQuestion(question.replace(/: *$/, '').trim());
  240.  
  241.         this.updateSensitivity(true);
  242.         this.emit('prompted');
  243.     }
  244.  
  245.     _onOVirtUserAuthenticated() {
  246.         if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
  247.             this.reset();
  248.     }
  249.  
  250.     _onSmartcardStatusChanged() {
  251.         this.smartcardDetected = this._userVerifier.smartcardDetected;
  252.  
  253.         // Most of the time we want to reset if the user inserts or removes
  254.         // a smartcard. Smartcard insertion "preempts" what the user was
  255.         // doing, and smartcard removal aborts the preemption.
  256.         // The exceptions are: 1) Don't reset on smartcard insertion if we're already verifying
  257.         //                        with a smartcard
  258.         //                     2) Don't reset if we've already succeeded at verification and
  259.         //                        the user is getting logged in.
  260.         if (this._userVerifier.serviceIsDefault(GdmUtil.SMARTCARD_SERVICE_NAME) &&
  261.             this.verificationStatus == AuthPromptStatus.VERIFYING &&
  262.             this.smartcardDetected)
  263.             return;
  264.  
  265.         if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
  266.             this.reset();
  267.     }
  268.  
  269.     _onShowMessage(userVerifier, message, type) {
  270.         this.setMessage(message, type);
  271.         this.emit('prompted');
  272.     }
  273.  
  274.     _onVerificationFailed(userVerifier, canRetry) {
  275.         this._queryingService = null;
  276.         this.clear();
  277.  
  278.         this.updateSensitivity(canRetry);
  279.         this.setActorInDefaultButtonWell(null);
  280.         this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
  281.  
  282.         Util.wiggle(this._entry);
  283.     }
  284.  
  285.     _onVerificationComplete() {
  286.         this.setActorInDefaultButtonWell(null);
  287.         this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED;
  288.         this.cancelButton.reactive = false;
  289.         this.cancelButton.can_focus = false;
  290.     }
  291.  
  292.     _onReset() {
  293.         this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
  294.         this.reset();
  295.     }
  296.  
  297.     setActorInDefaultButtonWell(actor, animate) {
  298.         if (!this._defaultButtonWellActor &&
  299.             !actor)
  300.             return;
  301.  
  302.         let oldActor = this._defaultButtonWellActor;
  303.  
  304.         if (oldActor)
  305.             oldActor.remove_all_transitions();
  306.  
  307.         let wasSpinner;
  308.         if (oldActor == this._spinner)
  309.             wasSpinner = true;
  310.         else
  311.             wasSpinner = false;
  312.  
  313.         let isSpinner;
  314.         if (actor == this._spinner)
  315.             isSpinner = true;
  316.         else
  317.             isSpinner = false;
  318.  
  319.         if (this._defaultButtonWellActor != actor && oldActor) {
  320.             if (!animate) {
  321.                 oldActor.opacity = 0;
  322.  
  323.                 if (wasSpinner) {
  324.                     if (this._spinner)
  325.                         this._spinner.stop();
  326.                 }
  327.             } else {
  328.                 oldActor.ease({
  329.                     opacity: 0,
  330.                     duration: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
  331.                     delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
  332.                     mode: Clutter.AnimationMode.LINEAR,
  333.                     onComplete: () => {
  334.                         if (wasSpinner) {
  335.                             if (this._spinner)
  336.                                 this._spinner.stop();
  337.                         }
  338.                     },
  339.                 });
  340.             }
  341.         }
  342.  
  343.         if (actor) {
  344.             if (isSpinner)
  345.                 this._spinner.play();
  346.  
  347.             if (!animate) {
  348.                 actor.opacity = 255;
  349.             } else {
  350.                 actor.ease({
  351.                     opacity: 255,
  352.                     duration: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
  353.                     delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
  354.                     mode: Clutter.AnimationMode.LINEAR,
  355.                 });
  356.             }
  357.         }
  358.  
  359.         this._defaultButtonWellActor = actor;
  360.     }
  361.  
  362.     startSpinning() {
  363.         this.setActorInDefaultButtonWell(this._spinner, true);
  364.     }
  365.  
  366.     stopSpinning() {
  367.         this.setActorInDefaultButtonWell(null, false);
  368.     }
  369.  
  370.     clear() {
  371.         this._entry.text = '';
  372.         this.stopSpinning();
  373.     }
  374.  
  375.     setQuestion(question) {
  376.         this._entry.hint_text = question;
  377.  
  378.         this._entry.show();
  379.         this._entry.grab_key_focus();
  380.     }
  381.  
  382.     getAnswer() {
  383.         let text;
  384.  
  385.         if (this._preemptiveAnswer) {
  386.             text = this._preemptiveAnswer;
  387.             this._preemptiveAnswer = null;
  388.         } else {
  389.             text = this._entry.get_text();
  390.         }
  391.  
  392.         return text;
  393.     }
  394.  
  395.     _fadeOutMessage() {
  396.         if (this._message.opacity == 0)
  397.             return;
  398.         this._message.remove_all_transitions();
  399.         this._message.ease({
  400.             opacity: 0,
  401.             duration: MESSAGE_FADE_OUT_ANIMATION_TIME,
  402.             mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  403.         });
  404.     }
  405.  
  406.     setMessage(message, type) {
  407.         if (type == GdmUtil.MessageType.ERROR)
  408.             this._message.add_style_class_name('login-dialog-message-warning');
  409.         else
  410.             this._message.remove_style_class_name('login-dialog-message-warning');
  411.  
  412.         if (type == GdmUtil.MessageType.HINT)
  413.             this._message.add_style_class_name('login-dialog-message-hint');
  414.         else
  415.             this._message.remove_style_class_name('login-dialog-message-hint');
  416.  
  417.         if (message) {
  418.             this._message.remove_all_transitions();
  419.             this._message.text = message;
  420.             this._message.opacity = 255;
  421.         } else {
  422.             this._message.opacity = 0;
  423.         }
  424.     }
  425.  
  426.     updateSensitivity(sensitive) {
  427.         this._entry.reactive = sensitive;
  428.     }
  429.  
  430.     vfunc_hide() {
  431.         this.setActorInDefaultButtonWell(null, true);
  432.         super.vfunc_hide();
  433.         this._message.opacity = 0;
  434.  
  435.         this.setUser(null);
  436.  
  437.         this.updateSensitivity(true);
  438.         this._entry.set_text('');
  439.     }
  440.  
  441.     setUser(user) {
  442.         let oldChild = this._userWell.get_child();
  443.         if (oldChild)
  444.             oldChild.destroy();
  445.  
  446.         let userWidget = new UserWidget.UserWidget(user, Clutter.Orientation.VERTICAL);
  447.         this._userWell.set_child(userWidget);
  448.  
  449.         if (!user)
  450.             this._updateEntry(false);
  451.     }
  452.  
  453.     reset() {
  454.         let oldStatus = this.verificationStatus;
  455.         this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
  456.         this.cancelButton.reactive = this._hasCancelButton;
  457.         this.cancelButton.can_focus = this._hasCancelButton;
  458.         this._preemptiveAnswer = null;
  459.  
  460.         if (this._userVerifier)
  461.             this._userVerifier.cancel();
  462.  
  463.         this._queryingService = null;
  464.         this.clear();
  465.         this._message.opacity = 0;
  466.         this.setUser(null);
  467.         this._updateEntry(true);
  468.         this.stopSpinning();
  469.  
  470.         if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED)
  471.             this.emit('failed');
  472.  
  473.         let beginRequestType;
  474.  
  475.         if (this._mode == AuthPromptMode.UNLOCK_ONLY) {
  476.             // The user is constant at the unlock screen, so it will immediately
  477.             // respond to the request with the username
  478.             beginRequestType = BeginRequestType.PROVIDE_USERNAME;
  479.         } else if (this._userVerifier.serviceIsForeground(GdmUtil.OVIRT_SERVICE_NAME) ||
  480.                    this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
  481.             // We don't need to know the username if the user preempted the login screen
  482.             // with a smartcard or with preauthenticated oVirt credentials
  483.             beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME;
  484.         } else {
  485.             // In all other cases, we should get the username up front.
  486.             beginRequestType = BeginRequestType.PROVIDE_USERNAME;
  487.         }
  488.  
  489.         this.emit('reset', beginRequestType);
  490.     }
  491.  
  492.     addCharacter(unichar) {
  493.         if (!this._entry.visible)
  494.             return;
  495.  
  496.         this._entry.grab_key_focus();
  497.         this._entry.clutter_text.insert_unichar(unichar);
  498.     }
  499.  
  500.     begin(params) {
  501.         params = Params.parse(params, { userName: null,
  502.                                         hold: null });
  503.  
  504.         this.updateSensitivity(false);
  505.  
  506.         let hold = params.hold;
  507.         if (!hold)
  508.             hold = new Batch.Hold();
  509.  
  510.         this._userVerifier.begin(params.userName, hold);
  511.         this.verificationStatus = AuthPromptStatus.VERIFYING;
  512.     }
  513.  
  514.     finish(onComplete) {
  515.         if (!this._userVerifier.hasPendingMessages) {
  516.             this._userVerifier.clear();
  517.             onComplete();
  518.             return;
  519.         }
  520.  
  521.         let signalId = this._userVerifier.connect('no-more-messages', () => {
  522.             this._userVerifier.disconnect(signalId);
  523.             this._userVerifier.clear();
  524.             onComplete();
  525.         });
  526.     }
  527.  
  528.     cancel() {
  529.         if (this.verificationStatus == AuthPromptStatus.VERIFICATION_SUCCEEDED)
  530.             return;
  531.  
  532.         this.reset();
  533.         this.emit('cancelled');
  534.     }
  535. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement