def _set_subscription_key(self, service_name, use_robocloud_vault): common_key = "AZURE_SUBSCRIPTION_KEY" service_key = f"AZURE_{service_name.upper()}_KEY" sub_key = None if use_robocloud_vault: vault = Secrets() vault_items = vault.get_secret(self.robocloud_vault_name) vault_items = {k.upper(): v for (k, v) in vault_items.items()} if service_key in vault_items and vault_items[service_key].strip( ) != "": sub_key = vault_items[service_key] elif common_key in vault_items and vault_items[common_key].strip( ) != "": sub_key = vault_items[common_key] if sub_key is None: raise KeyError( "The 'robocloud_vault_name' is required to access " "Robocloud Vault. Set them in library " "init or with `set_robocloud_vault` keyword.") else: sub_key = os.getenv(service_key) if sub_key is None or sub_key.strip() == "": sub_key = os.getenv(common_key) if sub_key is None or sub_key.strip() == "": raise KeyError( "Azure service key is required to use Azure Cloud " "service: %s" % service_name) self.services[service_name] = sub_key
def __init__(self): self._secrets = Secrets() self._key = None listener = RobotLogListener() listener.register_protected_keywords( ["RPA.Crypto.generate_key", "RPA.Crypto.use_encryption_key"] )
def get_wicksly_info(tracking_number): secrets = Secrets() USER_NAME = secrets.get_secret("credentials")["PLATFORM_USERNAME"] PASSWORD = secrets.get_secret("credentials")["PLATFORM_PASS"] with sync_playwright() as playwright: browser = playwright.chromium.launch(headless=False) wicksly_context = browser.newContext() w_page = wicksly_context.newPage() w_page.goto(os.environ.get('PLATFORM_URL')) w_page.fill('#id_username', USER_NAME) w_page.fill('#id_password', PASSWORD) with w_page.expect_navigation(): w_page.click('input[type=submit]') w_page.goto(os.environ.get('PLATFORM_URL')) w_page.fill('#searchbar', tracking_number) with w_page.expect_navigation(): w_page.click('text=Search') w_page.querySelectorAll('table#result_list tbody tr a')[0].click() street = w_page.getAttribute('#id_street1', 'value') city = w_page.getAttribute('#id_city', 'value') state = w_page.getAttribute('#id_state', 'value') postal_code = w_page.getAttribute('#id_postal_code', 'value') return { 'street': street, 'city': city, 'state': state, 'postal_code': postal_code }
def _init_client( self, service_name: str, aws_key_id: str = None, aws_key: str = None, region: str = None, use_robocloud_vault: bool = False, ): if region is None: region = self.region if use_robocloud_vault: vault = Secrets() vault_items = vault.get_secret(self.robocloud_vault_name) vault_items = {k.upper(): v for (k, v) in vault_items.items()} aws_key_id = vault_items["AWS_KEY_ID"] aws_key = vault_items["AWS_KEY"] else: if aws_key_id is None or aws_key_id.strip() == "": aws_key_id = required_env("AWS_KEY_ID") if aws_key is None or aws_key.strip() == "": aws_key = required_env("AWS_KEY") if (aws_key_id is None or aws_key_id.strip() == "" or aws_key is None or aws_key.strip() == ""): raise KeyError("AWS key ID and secret access key are required " " to use AWS cloud service: %s" % service_name) client = boto3.client( service_name, region_name=region, aws_access_key_id=aws_key_id, aws_secret_access_key=aws_key, ) self._set_service(service_name, client)
def login(page): page.goto(sales_navigator_login_url) page.waitForLoadState('load') secrets = Secrets() USER_NAME = secrets.get_secret("credentials")["LINKEDIN_EMAIL"] PASSWORD = secrets.get_secret("credentials")["LINKEDIN_PASSWORD"] page.fill('input#username', USER_NAME) page.fill('input#password', PASSWORD) page.click('button[type=submit]')
def test_file_secret_manager(monkeypatch): monkeypatch.setenv("RPA_SECRET_MANAGER", "RPA.Robocloud.Secrets.FileSecrets") monkeypatch.setenv("RPA_SECRET_FILE", "tests/resources/secrets.json") from RPA.Robocloud.Secrets import Secrets sm = Secrets() assert sm.secretmanager == "RPA.Robocloud.Secrets.FileSecrets" secrets = sm.get_secret("credentials") assert secrets["sap"]["login"] == "robot" assert secrets["sap"]["password"] == "secret" assert secrets["google"]["apikey"] == "1234567890"
def _get_service_account_from_robocloud(self): temp_filedesc = None if self.robocloud_vault_name is None or self.robocloud_vault_secret_key is None: raise KeyError( "Both 'robocloud_vault_name' and 'robocloud_vault_secret_key' " "are required to access Robocloud Vault. Set them in library " "init or with `set_robocloud_vault` keyword." ) vault = Secrets() vault_items = vault.get_secret(self.robocloud_vault_name) secret = json.loads(vault_items[self.robocloud_vault_secret_key].strip()) with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_filedesc: json.dump(secret, temp_filedesc, ensure_ascii=False) return temp_filedesc.name
def _init_with_robocloud(self, client_object, service_name): temp_filedesc = None if self.robocloud_vault_name is None or self.robocloud_vault_secret_key is None: raise KeyError( "Both 'robocloud_vault_name' and 'robocloud_vault_secret_key' " "are required to access Robocloud Vault. Set them in library " "init or with `set_robocloud_vault` keyword." ) vault = Secrets() try: vault_items = vault.get_secret(self.robocloud_vault_name) secret = json.loads(vault_items[self.robocloud_vault_secret_key].strip()) with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_filedesc: json.dump(secret, temp_filedesc, ensure_ascii=False) client = client_object.from_service_account_json(temp_filedesc.name) self._set_service(service_name, client) finally: if temp_filedesc: os.remove(temp_filedesc.name)
def test_secrets_custom_adapter_arguments(mock_env_default): library = Secrets("pos-value", key="key-value", default_adapter=MockAdapter) library.get_secret("not-relevant") # Adapter created on first request assert MockAdapter.args == (("pos-value", ), {"key": "key-value"})
def test_secrets_vault_missing_token(mock_env_default, mock_env_vault, monkeypatch): monkeypatch.delenv("RC_API_SECRET_TOKEN", raising=False) library = Secrets() with pytest.raises(KeyError): _ = library.adapter
def test_secrets_vault_as_default(mock_env_default, mock_env_vault): library = Secrets() assert isinstance(library.adapter, RobocloudVault)
''' Variables for Robot Framework goes here. ''' import calendar from datetime import date from RPA.Robocloud.Secrets import Secrets WEEK_DAY_NAME = calendar.day_name[date.today().weekday()] secrets = Secrets() GA_UCC_USERNAME = secrets.get_secret("ga_ucc_creds")["username"] GA_UCC_PASSWORD = secrets.get_secret("ga_ucc_creds")["password"]
def __init__(self): super().__init__() self.dbx = dropbox.Dropbox( Secrets().get_secret("Dropbox")["ACCESS_TOKEN"])
def test_not_existing_class_as_secret_manager(monkeypatch): monkeypatch.setenv("RPA_SECRET_MANAGER", "RPA.NotExistingSecretManager") from RPA.Robocloud.Secrets import Secrets with pytest.raises(Exception): Secrets()
from RPA.Email.ImapSmtp import ImapSmtp from RPA.Robocloud.Secrets import Secrets secrets = Secrets() secret = secrets.get_secret("emailCredentials") gmail_account = secret["username"] gmail_password = secret["password"] def send_email(recipient, subject, body): mail = ImapSmtp(smtp_server="smtp.gmail.com", smtp_port=587) mail.authorize(account=gmail_account, password=gmail_password) mail.send_message( sender=gmail_account, recipients=recipient, subject=subject, body=body, )
def test_invalid_base_class_as_secret_manager(monkeypatch): monkeypatch.setenv("RPA_SECRET_MANAGER", "RPA.Trollo") from RPA.Robocloud.Secrets import Secrets with pytest.raises(Exception): Secrets()
def test_use_secret_manager_when_environment_is_not_set(monkeypatch): monkeypatch.delenv("RPA_SECRET_MANAGER", raising=False) from RPA.Robocloud.Secrets import Secrets sm = Secrets() assert sm.secretmanager == "RPA.Robocloud.Secrets.RobocloudVault"
import os from pathlib import Path import shutil import sys from RPA.Archive import Archive from RPA.Browser import Browser from RPA.FileSystem import FileSystem from RPA.PDF import PDF from RPA.Robocloud.Secrets import Secrets from RPA.Robocloud.Items import Items archive = Archive() browser = Browser() pdf = PDF() secretmanager = Secrets() workitems = Items() files = FileSystem() output_dir = Path(".") / "output" image_dir = output_dir / "images" pdf_dir = output_dir / "pdfs" def main(): """Robot workflow actions.""" all_steps_done = False try: clear_previous_run() # this can be skipped open_page() log_in()
def test_secrets_adapter_invalid_baseclass(mock_env_default): with pytest.raises(ValueError): Secrets(default_adapter=InvalidBaseClass)
def get_and_display_secrets(credential: str): secrets = Secrets() user_details = secrets.get_secret(credential)["username"] print(user_details)
''' Variables for Robot Framework goes here. ''' import calendar from datetime import date # + from RPA.Robocloud.Secrets import Secrets secrets = Secrets() USER_NAME = secrets.get_secret("credentials")["username"] PASSWORD = secrets.get_secret("credentials")["password"] # - WEEK_DAY_NAME = calendar.day_name[date.today().weekday()]
from RPA.Robocloud.Secrets import Secrets EXCEL_FILE_PATH = __file__ + "/../../devdata/Data.xlsx" SWAG_LABS_URL = "https://www.saucedemo.com" secrets = Secrets() SWAG_LABS_USER_NAME = secrets.get_secret("swaglabs")["username"] SWAG_LABS_PASSWORD = secrets.get_secret("swaglabs")["password"]
def test_secrets_custom_adapter_get_secret(mock_env_default): MockAdapter.value = "mock-secret" library = Secrets(default_adapter=MockAdapter) assert library.get_secret("mock-name") == "mock-secret" assert MockAdapter.name == "mock-name"
def test_secrets_adapter_missing_import(monkeypatch): monkeypatch.setenv("RPA_SECRET_MANAGER", "RPA.AdapterNotExist") with pytest.raises(ValueError): Secrets()
class Crypto: """Library for common encryption and hashing operations. It uses the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ format for encryption. More specifically, it uses AES in CBC mode with a 128-bit key for encryption and HMAC with SHA256 for authentication. To use the encryption features, generate a key with the command line utility ``rpa-crypto`` or with the keyword ``Generate Key``. Store the key in a secure place, such as Robocorp Vault, and load it within the execution before calling encryption/decryption keywords. **Example usage with Robocorp Vault** Create an encryption key with the CLI utility: .. code-block:: console > rpa-crypto key rGx1edA07yz7uD08ChiPSunn8vaauRxw0pAbsal9zjM= Store the key in Robocorp Vault, in this case with the name ``EncryptionKey``. Load the key from the vault before encryption operations: .. code-block:: robotframework Use encryption key from vault EncryptionKey ${encrypted}= Encrypt file orders.xlsx Add work item file ${encrypted} name=Orders In another task, this same key can be used to decrypt the file: .. code-block:: robotframework Use encryption key from vault EncryptionKey ${encrypted}= Get work item file Orders ${orders}= Decrypt file ${encrypted} """ ROBOT_LIBRARY_SCOPE = "GLOBAL" ROBOT_LIBRARY_DOC_FORMAT = "REST" def __init__(self): self._secrets = Secrets() self._key = None listener = RobotLogListener() listener.register_protected_keywords( ["RPA.Crypto.generate_key", "RPA.Crypto.use_encryption_key"] ) def generate_key(self) -> str: """Generate a Fernet encryption key as base64 string. This key can be used for encryption/decryption operations with this library. *NOTE:* Store the generated key in a secure place! If the key is lost, the encrypted data can not be recovered. If anyone else gains access to it, they can decrypt your data. """ return Fernet.generate_key().decode("utf-8") def use_encryption_key(self, key: str): """Set key for all following encryption/decryption operations. :param key: Encryption key as base64 string Assumes the given key has been generated previously using either the keyword ``Generate Key`` or with the matching command line utility. Example: .. code-block:: robotframework ${key}= Read file encryption.key Use encryption key ${key} """ self._key = Fernet(key) def use_encryption_key_from_vault(self, name: str, key: Optional[str] = None): """Load an encryption key from Robocorp Vault. :param name: Name of secret in Vault :param key: Name of encryption key in secret If the secret only has one value, the key argument is optional. Example: .. code-block:: robotframework # Secret with one value Use encryption key from vault Encryption # Secret with multiple values Use encryption key from vault name=Encryption key=CryptoKey """ secret = self._secrets.get_secret(name) if key: value = secret[key] elif len(secret) == 1: value = list(secret.values())[0] elif len(secret) == 0: raise ValueError(f"Secret '{name}' has no values") else: options = ", ".join(str(k) for k in secret.keys()) raise ValueError(f"Secret '{name}' has multiple values: {options}") self.use_encryption_key(value) def hash_string(self, text: str, method: Hash = Hash.SHA1, encoding="utf-8") -> str: """Calculate a hash from a string, in base64 format. :param text: String to hash :param method: Used hashing method :param encoding: Used text encoding Example: .. code-block:: robotframework ${digest}= Hash string A value that will be hashed Should be equal ${digest} uSlyRHlbu8NzY29YMZhDUpdErP4= """ if isinstance(text, str): text = text.encode(encoding) context = to_hash_context(method) context.update(text) digest = context.finalize() return base64.b64encode(digest).decode("utf-8") def hash_file(self, path: str, method: Hash = Hash.SHA1) -> str: """Calculate a hash from a file, in base64 format. :param path: Path to file :param method: The used hashing method Example: .. code-block:: robotframework ${digest}= Hash file orders.xlsx method=MD5 Should not be equal ${digest} uSlyRHlbu8NzY29YMZhDUpdErP4= """ context = to_hash_context(method) with open(path, "rb") as infile: while True: chunk = infile.read(65536) if not chunk: break context.update(chunk) digest = context.finalize() return base64.b64encode(digest).decode("utf-8") def encrypt_string(self, text: Union[bytes, str], encoding="utf-8") -> bytes: """Encrypt a string. :param text: Source text to encrypt :param encoding: Used text encoding Example: .. code-block:: robotframework Use encryption key ${key} ${token}= Encrypt string This is a secret, don't share it """ if not self._key: raise ValueError("No encryption key set") if isinstance(text, str): text = text.encode(encoding) token = self._key.encrypt(text) return token def decrypt_string( self, data: Union[bytes, str], encoding="utf-8" ) -> Union[str, bytes]: """Decrypt a string. :param data: Encrypted data as base64 string :param encoding: Original encoding of string Returns the decrypted string that is parsed with the given encoding, or if the encoding is ``None`` the raw bytes are returned. Example: .. code-block:: robotframework Use encryption key ${key} ${text}= Decrypt string ${token} Log Secret string is: ${text} """ if not self._key: raise ValueError("No encryption key set") if isinstance(data, str): data = data.encode("utf-8") try: text = self._key.decrypt(data) except InvalidToken as err: raise ValueError( "Failed to decrypt string (malformed content or invalid signature)" ) from err if encoding is not None: text = text.decode(encoding) return text def encrypt_file(self, path: str, output: Optional[str] = None) -> str: """Encrypt a file. :param path: Path to source input file :param output: Path to encrypted output file If not output path is given, it will generate one from the input path. The resulting output path is returned. Example: .. code-block:: robotframework Use encryption key ${key} ${path}= Encrypt file orders.xlsx Log Path to encrypted file is: ${path} """ path = Path(path) if not self._key: raise ValueError("No encryption key set") if output: output = Path(output) else: output = path.parent / (path.name + ".enc") with open(path, "rb") as infile: data = infile.read() token = self._key.encrypt(data) with open(output, "wb") as outfile: outfile.write(token) return str(output) def decrypt_file(self, path: str, output: Optional[str] = None) -> str: """Decrypt a file. :param path: Path to encrypted input file :param output: Path to decrypted output file If not output path is given, it will generate one from the input path. The resulting output path is returned. Example: .. code-block:: robotframework Use encryption key ${key} ${path}= Decrypt file orders.xlsx.enc Log Path to decrypted file is: ${path} """ path = Path(path) if not self._key: raise ValueError("No encryption key set") if output: output = Path(output) elif path.name.endswith(".enc"): output = path.parent / path.name[: -len(".enc")] else: parts = (path.stem, "dec", path.suffix[1:]) output = path.parent / ".".join(part for part in parts if part.strip()) try: with open(path, "rb") as infile: token = infile.read() data = self._key.decrypt(token) except InvalidToken as err: raise ValueError( "Failed to decrypt file (malformed content or invalid signature)" ) from err with open(output, "wb") as outfile: outfile.write(data) return str(output)
from RPA.Robocloud.Secrets import Secrets secrets = Secrets() USER_NAME = secrets.get_secret("CaptureFastCredentials")["username"] PASSWORD = secrets.get_secret("CaptureFastCredentials")["password"] TEAMID = secrets.get_secret("CaptureFastCredentials")["teamid"]
from RPA.Robocloud.Secrets import Secrets # Set global variable for local file path for Order backlog (CSV file) CSV_LOCAL_FILE_PATH = "./output/orders.csv" # Use vault to store secret URLs for RobotSpareBin website and Order backlog (CSV file) secrets = Secrets() WEBSITE_URL = secrets.get_secret("ROBOTSPAREBIN")["WEBSITE_URL"] CSV_URL = secrets.get_secret("ROBOTSPAREBIN")["CSV_URL"]