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 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 _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_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 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"})
''' 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"]
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)
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"]
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_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"
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"]