Пример #1
0
    def from_file(filename: str):
        decoded_data = decode(Image.open(filename))
        if path.isfile(filename):
            remove(filename)
        try:
            # See https://github.com/google/google-authenticator/wiki/Key-Uri-Format
            # for a description of the URL format
            url = urlparse(decoded_data[0].data.decode())
            query_params = parse_qsl(url.query)
            url_data = dict(query_params)

            username = None
            label = unquote(url.path.lstrip("/"))
            if ":" in label:
                provider, username = label.split(":", maxsplit=1)
            else:
                provider = label
            # provider information could also be in the query params
            provider = url_data.get("issuer", provider)

            token = url_data.get("secret")
            assert OTP.is_valid(token)

            return {
                'username': username,
                'provider': provider,
                'token': token
            }
        except (KeyError, IndexError):
            Logger.error("Invalid QR image")
Пример #2
0
 def search_accounts(self, terms):
     if terms:
         filters = " ".join(terms)
         if filters:
             filters = "%" + filters + "%"
         query = """
                     SELECT A.* FROM accounts A
                     JOIN providers P
                     ON A.provider = P.id
                     WHERE
                     A.username LIKE ?
                     OR
                     P.name LIKE ?
                     GROUP BY provider
                     ORDER BY  A.username ASC
                 """
         try:
             data = self.conn.cursor().execute(query, (
                 filters,
                 filters,
             ))
             accounts = data.fetchall()
             return [Account(*account) for account in accounts]
         except Exception as error:
             Logger.error("[SQL]: Couldn't search for an account")
             Logger.error(str(error))
     return []
Пример #3
0
 def remove(self):
     """
     Remove the account.
     """
     Database.get_default().delete_account(self.id)
     Keyring.get_default().remove(self._token_id)
     self.emit("removed")
     Logger.debug("Account '{}' with id {} was removed".format(
         self.username, self.id))
Пример #4
0
 def __count(self, table_name: str) -> int:
     query = "SELECT COUNT(id) AS count FROM " + table_name
     try:
         data = self.conn.cursor().execute(query)
         return data.fetchone()[0]
     except Exception as error:
         Logger.error("[SQL]: Couldn't count the results from " + table_name)
         Logger.error(str(error))
     return None
Пример #5
0
 def import_accounts(accounts: [dict]):
     accounts_widget = AccountsWidget.get_default()
     accounts_manager = AccountsManager.get_default()
     for account in accounts:
         try:
             new_account = Account.create_from_json(account)
             accounts_manager.add(new_account.provider, new_account)
             accounts_widget.append(new_account)
         except Exception as e:
             Logger.error("[Restore] Failed to import accounts")
             Logger.error(str(e))
Пример #6
0
 def _setup_css(self):
     """Setup the CSS and load it."""
     Logger.debug("Loading CSS")
     provider = Gtk.CssProvider()
     provider.load_from_resource(
         '/com/github/bilelmoussaoui/Authenticator/style.css')
     Gtk.StyleContext().add_provider_for_screen(
         Gdk.Screen.get_default(), provider,
         Gtk.STYLE_PROVIDER_PRIORITY_USER)
     Gtk.IconTheme.get_default().add_resource_path(
         "/com/github/bilelmoussaoui/Authenticator/icons")
Пример #7
0
 def get_providers(self, **kwargs):
     only_used = kwargs.get("only_used", )
     query = "SELECT * FROM providers"
     if only_used:
         query += " WHERE id IN (SELECT DISTINCT provider FROM accounts)"
     try:
         data = self.conn.cursor().execute(query)
         providers = data.fetchall()
         return [Provider(*provider) for provider in providers]
     except Exception as error:
         Logger.error("[SQL] Couldn't fetch providers list")
         Logger.error(str(error))
     return None
Пример #8
0
 def provider_by_id(self, id_):
     """
         Get a provider by the ID
         :param id_: int the provider id
         :return: Provider: The provider data
     """
     query = "SELECT * FROM providers WHERE id=?"
     try:
         data = self.conn.cursor().execute(query, (id_, ))
         return Provider(*data.fetchone())
     except Exception as error:
         Logger.error("[SQL] Couldn't get provider with ID={}".format(id_))
         Logger.error(str(error))
     return None
Пример #9
0
    def __delete(self, table_name, id_):
        """
            Remove a row by ID.

            :param id_: the row ID
            :type id_: int
        """
        query = "DELETE FROM {} WHERE id=?".format(table_name)
        try:
            self.conn.execute(query, (id_, ))
            self.conn.commit()
        except Exception as error:
            Logger.error("[SQL] Couldn't remove the row '{}'".format(id_))
            Logger.error(str(error))
Пример #10
0
 def account_by_id(self, id_):
     """
         Get an account by the ID
         :param id_: int the account id
         :return: Account: The account data
     """
     query = "SELECT * FROM accounts WHERE id=?"
     try:
         data = self.conn.cursor().execute(query, (id_, ))
         return Account(*data.fetchone())
     except Exception as error:
         Logger.error("[SQL] Couldn't get account with ID={}".format(id_))
         Logger.error(str(error))
     return None
Пример #11
0
    def accounts(self):
        """
            Retrieve the list of accounts.

            :return list
        """
        query = "SELECT * FROM accounts"
        try:
            data = self.conn.cursor().execute(query)
            accounts = data.fetchall()
            return [Account(*account) for account in accounts]
        except Exception as error:
            Logger.error("[SQL] Couldn't fetch accounts list")
            Logger.error(str(error))
        return None
Пример #12
0
 def __init__(self, _id, username, token_id, provider):
     GObject.GObject.__init__(self)
     self.id = _id
     self.username = username
     self.provider = provider
     self._token_id = token_id
     token = Keyring.get_default().get_by_id(self._token_id)
     self.connect("otp_out_of_date", self._on_otp_out_of_date)
     if token:
         self.otp = OTP(token)
         self._code_generated = True
     else:
         self.otp = None
         self._code_generated = False
         Logger.error("Could not read the secret code,"
                      "the keyring keys were reset manually")
Пример #13
0
 def insert_account(self, username, token_id, provider):
     """
     Insert a new account to the database
     :param username: Account name
     :param token_id: The token identifier stored using libsecret
     :param provider: The provider foreign key
     """
     query = "INSERT INTO accounts (username, token_id, provider) VALUES (?, ?, ?)"
     cursor = self.conn.cursor()
     try:
         cursor.execute(query, [username, token_id, provider])
         self.conn.commit()
         return Account(cursor.lastrowid, username, token_id, provider)
     except Exception as error:
         Logger.error("[SQL] Couldn't add a new account")
         Logger.error(str(error))
Пример #14
0
 def provider_by_name(self, provider_name: str) -> Provider:
     """
         Get a provider by the ID
         :param id_: int the provider id
         :return: Provider: The provider data
     """
     query = "SELECT * FROM providers WHERE name LIKE ? "
     try:
         data = self.conn.cursor().execute(query, (provider_name, ))
         provider = data.fetchone()
         return Provider(*provider) if provider else None
     except Exception as error:
         Logger.error("[SQL] Couldn't get provider with name={}".format(
             provider_name))
         Logger.error(str(error))
     return None
Пример #15
0
 def insert_provider(self, name, website, doc_url=None, image=None):
     """
     Insert a new provider to the database
     :param name: The provider name
     :param website: The provider website, used to extract favicon
     :param doc_url: The provider doc_url, used to allow user get the docs
     :param image: The image path of a provider
     """
     query = "INSERT INTO providers (name, website, doc_url, image) VALUES (?, ?, ?, ?)"
     cursor = self.conn.cursor()
     try:
         cursor.execute(query, [name, website, doc_url, image])
         self.conn.commit()
         return Provider(cursor.lastrowid, name, website, doc_url, image)
     except Exception as error:
         Logger.error("[SQL] Couldn't add a new account")
         Logger.error(str(error))
Пример #16
0
    def restore_state(self):
        """
            Restore the window's state.
        """
        settings = Settings.get_default()
        # Restore the window position
        position_x, position_y = settings.window_position
        if position_x != 0 and position_y != 0:
            self.move(position_x, position_y)
            Logger.debug("[Window] Restore position x: {}, y: {}".format(
                position_x, position_y))
        else:
            # Fallback to the center
            self.set_position(Gtk.WindowPosition.CENTER)

        if settings.window_maximized:
            self.maximize()
Пример #17
0
 def __update_by_id(self, table_name, data, id_):
     query = "UPDATE {} SET ".format(table_name)
     resources = []
     i = 0
     for table_column, value in data.items():
         query += " {}=?".format(table_column)
         if i != len(data) - 1:
             query += ","
         resources.append(value)
         i += 1
     resources.append(id_)
     query += "WHERE id=?"
     try:
         self.conn.execute(query, resources)
         self.conn.commit()
     except Exception as error:
         Logger.error("[SQL] Couldn't update row by id")
         Logger.error(error)
Пример #18
0
    def read(self):
        decoded_data = decode(Image.open(self.filename))
        if path.isfile(self.filename):
            remove(self.filename)
        try:
            # See https://github.com/google/google-authenticator/wiki/Key-Uri-Format
            # for a description of the URL format
            url = urlparse(decoded_data[0].data.decode())
            query_params = parse_qsl(url.query)
            self._codes = dict(query_params)

            label = unquote(url.path.lstrip("/"))
            if ":" in label:
                self.provider, self.username = label.split(":", maxsplit=1)
            else:
                self.provider = label
            # provider information could also be in the query params
            self.provider = self._codes.get("issuer", self.provider)

            return self._codes.get("secret")
        except (KeyError, IndexError):
            Logger.error("Invalid QR image")
            return None
Пример #19
0
 Authenticator is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Authenticator. If not, see <http://www.gnu.org/licenses/>.
"""
import binascii

from Authenticator.models import Logger

try:
    from pyotp import TOTP
except ImportError:
    Logger.error("Impossible to import TOTP, please install PyOTP first")


class OTP(TOTP):
    """
        OTP (One-time password) handler using PyOTP.
    """

    def __init__(self, token):
        """
        :param token: the OTP token.
        """
        TOTP.__init__(self, token)
        self.pin = None
        self.update()
Пример #20
0
    parser = argparse.ArgumentParser(prog="Authenticator")
    parser.add_argument("--debug",
                        "-d",
                        action="store_true",
                        help=_("Start in debug mode"))
    args = parser.parse_args()

    resource = Gio.resource_load(
        path.join('/usr/share/com.github.bilelmoussaoui.Authenticator',
                  'com.github.bilelmoussaoui.Authenticator.gresource'))
    Gio.Resource._register(resource)

    from Authenticator.models import Logger
    level = Logger.ERROR
    if args.debug:
        level = Logger.DEBUG
        import faulthandler
        faulthandler.enable()

    Logger.set_level(level)
    try:
        Handy.init(None)
        from Authenticator.application import Application
        app = Application.get_default()
        app.props.profile = 'default'
        exit_status = app.run(None)
        sys.exit(exit_status)
    except KeyboardInterrupt:
        exit()