Coverage for frappe_manager / ssl_manager / ssl_utils.py: 0%

48 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-07-02 18:35 +0530

1""" 

2SSL Manager utility functions for credentials and configuration management. 

3""" 

4 

5from typing import TYPE_CHECKING, Optional 

6 

7if TYPE_CHECKING: 

8 from frappe_manager.site_manager.bench_config import BenchConfig 

9 

10from frappe_manager.metadata_manager import FMConfigManager 

11from frappe_manager.ssl_manager import LETSENCRYPT_PREFERRED_CHALLENGE 

12from frappe_manager.ssl_manager.certificate import SSLCertificate 

13from frappe_manager.ssl_manager.certificate_exceptions import SSLDNSChallengeCredentailsNotFound 

14 

15 

16def get_dns_credentials_for_certificate( 

17 certificate: SSLCertificate, 

18 bench_config: Optional["BenchConfig"] = None, 

19) -> dict[str, str] | None: 

20 """ 

21 Load DNS credentials and format for acme.sh. 

22 

23 Checks credentials in this order: 

24 1. Bench-level DNS provider config (if bench_config provided) 

25 2. Global FM config 

26 3. Certificate-specific credentials (api_token/api_key on cert object) 

27 

28 This function retrieves Cloudflare API credentials and formats them as 

29 environment variables for acme.sh dns_cf plugin. 

30 

31 Args: 

32 certificate: Certificate configuration 

33 bench_config: Optional bench configuration for bench-level credentials 

34 

35 Returns: 

36 Dictionary of environment variables for acme.sh: 

37 - {'CF_Token': 'xxx'} for API token auth, or 

38 - {'CF_Key': 'xxx', 'CF_Email': 'xxx'} for global API key auth 

39 - None if not a DNS challenge 

40 

41 Raises: 

42 SSLDNSChallengeCredentailsNotFound: If DNS challenge requires credentials but none found 

43 

44 Example: 

45 >>> cert = SSLCertificate(domain="example.com", challenge_type=LETSENCRYPT_PREFERRED_CHALLENGE.dns01) 

46 >>> creds = get_dns_credentials_for_certificate(cert, bench_config) 

47 >>> # Use creds with acme.sh service 

48 >>> service.generate_certificate(cert, dns_credentials=creds) 

49 """ 

50 if certificate.challenge_type != LETSENCRYPT_PREFERRED_CHALLENGE.dns01: 

51 return None 

52 

53 credentials = {} 

54 

55 if bench_config and bench_config.dns_providers: 

56 cloudflare_config = bench_config.dns_providers.get("cloudflare") 

57 if cloudflare_config and cloudflare_config.exists: 

58 if cloudflare_config.api_token: 

59 credentials["CF_Token"] = cloudflare_config.api_token 

60 elif cloudflare_config.api_key: 

61 credentials["CF_Key"] = cloudflare_config.api_key 

62 if cloudflare_config.email: 

63 credentials["CF_Email"] = str(cloudflare_config.email) 

64 if credentials: 

65 return credentials 

66 

67 fm_config = FMConfigManager.import_from_toml() 

68 

69 if fm_config.cloudflare.api_token: 

70 credentials["CF_Token"] = fm_config.cloudflare.api_token 

71 elif fm_config.cloudflare.api_key: 

72 credentials["CF_Key"] = fm_config.cloudflare.api_key 

73 if fm_config.cloudflare.email: 

74 credentials["CF_Email"] = str(fm_config.cloudflare.email) 

75 

76 if not credentials: 

77 if hasattr(certificate, "api_token") and certificate.api_token: 

78 credentials["CF_Token"] = certificate.api_token 

79 elif hasattr(certificate, "api_key") and certificate.api_key: 

80 credentials["CF_Key"] = certificate.api_key 

81 if hasattr(certificate, "email") and certificate.email: 

82 credentials["CF_Email"] = str(certificate.email) 

83 

84 if not credentials: 

85 raise SSLDNSChallengeCredentailsNotFound() 

86 

87 return credentials 

88 

89 

90def get_dns_credentials_dict( 

91 api_token: str | None = None, 

92 api_key: str | None = None, 

93 email: str | None = None, 

94) -> dict[str, str]: 

95 """ 

96 Create DNS credentials dictionary from individual parameters. 

97 

98 Useful for explicitly passing credentials instead of loading from config. 

99 

100 Args: 

101 api_token: Cloudflare API token (preferred) 

102 api_key: Cloudflare Global API key (legacy) 

103 email: Email for Global API key auth 

104 

105 Returns: 

106 Dictionary formatted for acme.sh 

107 

108 Raises: 

109 SSLDNSChallengeCredentailsNotFound: If no valid credentials provided 

110 

111 Example: 

112 >>> creds = get_dns_credentials_dict(api_token="my_token_here") 

113 >>> service.generate_certificate(cert, dns_credentials=creds) 

114 """ 

115 credentials = {} 

116 

117 if api_token: 

118 credentials["CF_Token"] = api_token 

119 elif api_key: 

120 credentials["CF_Key"] = api_key 

121 if email: 

122 credentials["CF_Email"] = email 

123 

124 if not credentials: 

125 raise SSLDNSChallengeCredentailsNotFound( 

126 "No Cloudflare credentials provided. Need either api_token or (api_key + email)", 

127 ) 

128 

129 return credentials