From 0a1cf4d0e367b6dbfe18dee6ad1e2e167656f9a7 Mon Sep 17 00:00:00 2001 From: mandarons Date: Sat, 24 Feb 2024 16:07:17 +0000 Subject: [PATCH] deploy: 060d4e9179221903cc32b5966a6da9fad4e3785b --- test-coverage/index.html | 14 +- test-coverage/src___init___py.html | 2 +- test-coverage/src_config_parser_py.html | 34 +++- test-coverage/src_email_message_py.html | 2 +- test-coverage/src_notify_py.html | 231 ++++++++++++++---------- test-coverage/src_sync_drive_py.html | 2 +- test-coverage/src_sync_photos_py.html | 2 +- test-coverage/src_sync_py.html | 2 +- test-coverage/src_usage_py.html | 2 +- test-coverage/status.json | 2 +- 10 files changed, 178 insertions(+), 115 deletions(-) diff --git a/test-coverage/index.html b/test-coverage/index.html index afe35f128..d4d7e5a64 100644 --- a/test-coverage/index.html +++ b/test-coverage/index.html @@ -53,10 +53,10 @@

Coverage report: Total - 870 + 907 0 0 - 100% + 100% @@ -69,10 +69,10 @@

Coverage report: src/config_parser.py - 212 + 226 0 0 - 100% + 100% src/email_message.py @@ -83,10 +83,10 @@

Coverage report: src/notify.py - 68 + 91 0 0 - 100% + 100% src/sync.py @@ -126,7 +126,7 @@

Coverage report:

coverage.py v5.4, - created at 2024-02-23 16:41 +0000 + created at 2024-02-24 16:06 +0000

diff --git a/test-coverage/src___init___py.html b/test-coverage/src___init___py.html index 27c0d8e66..483190bf1 100644 --- a/test-coverage/src___init___py.html +++ b/test-coverage/src___init___py.html @@ -195,7 +195,7 @@

« index     coverage.py v5.4, - created at 2024-02-23 16:41 +0000 + created at 2024-02-24 16:06 +0000

diff --git a/test-coverage/src_config_parser_py.html b/test-coverage/src_config_parser_py.html index a460f07e3..f2d1bdae7 100644 --- a/test-coverage/src_config_parser_py.html +++ b/test-coverage/src_config_parser_py.html @@ -22,8 +22,8 @@

Coverage for src/config_parser.py :

Show keyboard shortcuts

- 212 statements   - + 226 statements   +

@@ -472,12 +472,40 @@

418 else: 

419 chat_id = get_config_value(config=config, config_path=config_path) 

420 return chat_id 

+

421 

+

422 

+

423# Get discord webhook_url 

+

424def get_discord_webhook_url(config): 

+

425 """Return discord webhook_url from config.""" 

+

426 webhook_url = None 

+

427 config_path = ["app", "discord", "webhook_url"] 

+

428 if not traverse_config_path(config=config, config_path=config_path): 

+

429 LOGGER.warning( 

+

430 f"Warning: webhook_url is not found in {config_path_to_string(config_path)}." 

+

431 ) 

+

432 else: 

+

433 webhook_url = get_config_value(config=config, config_path=config_path) 

+

434 return webhook_url 

+

435 

+

436 

+

437# Get discord username 

+

438def get_discord_username(config): 

+

439 """Return discord username from config.""" 

+

440 username = None 

+

441 config_path = ["app", "discord", "username"] 

+

442 if not traverse_config_path(config=config, config_path=config_path): 

+

443 LOGGER.warning( 

+

444 f"Warning: username is not found in {config_path_to_string(config_path)}." 

+

445 ) 

+

446 else: 

+

447 username = get_config_value(config=config, config_path=config_path) 

+

448 return username 

diff --git a/test-coverage/src_email_message_py.html b/test-coverage/src_email_message_py.html index a598f03ef..bfcfd19a6 100644 --- a/test-coverage/src_email_message_py.html +++ b/test-coverage/src_email_message_py.html @@ -108,7 +108,7 @@

« index     coverage.py v5.4, - created at 2024-02-23 16:41 +0000 + created at 2024-02-24 16:06 +0000

diff --git a/test-coverage/src_notify_py.html b/test-coverage/src_notify_py.html index 1d2733aa9..263a87e4a 100644 --- a/test-coverage/src_notify_py.html +++ b/test-coverage/src_notify_py.html @@ -22,8 +22,8 @@

Coverage for src/notify.py :

Show keyboard shortcuts

- 68 statements   - + 91 statements   +

@@ -61,110 +61,145 @@

7from src import LOGGER, config_parser 

8from src.email_message import EmailMessage as Message 

9 

-

10 

-

11def notify_telegram(config, last_send=None, dry_run=False): 

-

12 """Send telegram notification.""" 

-

13 sent_on = None 

-

14 bot_token = config_parser.get_telegram_bot_token(config=config) 

-

15 chat_id = config_parser.get_telegram_chat_id(config=config) 

-

16 

-

17 if last_send and last_send > datetime.datetime.now() - datetime.timedelta(hours=24): 

-

18 LOGGER.info("Throttling telegram to once a day") 

-

19 sent_on = last_send 

-

20 elif bot_token and chat_id: 

-

21 sent_on = datetime.datetime.now() 

-

22 if not dry_run: 

-

23 # Post message to telegram bot using API 

-

24 if not post_message_to_telegram( 

-

25 bot_token, 

-

26 chat_id, 

-

27 """Two-step authentication for iCloud Drive, Photos (Docker) is required. 

-

28 Please login to your server and authenticate. Please run - 

-

29 `docker exec -it icloud /bin/sh -c "icloud --username=<icloud-username> 

-

30 --session-directory=/app/session_data"`.""", 

-

31 ): 

-

32 sent_on = None 

-

33 else: 

-

34 LOGGER.warning( 

-

35 "Not sending 2FA notification because Telegram is not configured." 

-

36 ) 

-

37 return sent_on 

-

38 

-

39 

-

40def post_message_to_telegram(bot_token, chat_id, message): 

-

41 """Post message to telegram bot using API.""" 

-

42 url = f"https://api.telegram.org/bot{bot_token}/sendMessage" 

-

43 params = {"chat_id": chat_id, "text": message} 

-

44 response = requests.post(url, params=params, timeout=10) 

-

45 if response.status_code == 200: 

-

46 return True 

-

47 else: 

-

48 # Log error message 

-

49 LOGGER.error(f"Failed to send telegram notification. Response: {response.text}") 

-

50 return False 

-

51 

+

10MESSAGE_BODY = """Two-step authentication for iCloud Drive, Photos (Docker) is required. 

+

11 Please login to your server and authenticate. Please run - 

+

12 `docker exec -it icloud /bin/sh -c "icloud --username=<icloud-username> 

+

13 --session-directory=/app/session_data"`.""" 

+

14 

+

15 

+

16def notify_telegram(config, last_send=None, dry_run=False): 

+

17 """Send telegram notification.""" 

+

18 sent_on = None 

+

19 bot_token = config_parser.get_telegram_bot_token(config=config) 

+

20 chat_id = config_parser.get_telegram_chat_id(config=config) 

+

21 

+

22 if last_send and last_send > datetime.datetime.now() - datetime.timedelta(hours=24): 

+

23 LOGGER.info("Throttling telegram to once a day") 

+

24 sent_on = last_send 

+

25 elif bot_token and chat_id: 

+

26 sent_on = datetime.datetime.now() 

+

27 if not dry_run: 

+

28 # Post message to telegram bot using API 

+

29 if not post_message_to_telegram( 

+

30 bot_token, 

+

31 chat_id, 

+

32 MESSAGE_BODY, 

+

33 ): 

+

34 sent_on = None 

+

35 else: 

+

36 LOGGER.warning( 

+

37 "Not sending 2FA notification because Telegram is not configured." 

+

38 ) 

+

39 return sent_on 

+

40 

+

41 

+

42def post_message_to_telegram(bot_token, chat_id, message): 

+

43 """Post message to telegram bot using API.""" 

+

44 url = f"https://api.telegram.org/bot{bot_token}/sendMessage" 

+

45 params = {"chat_id": chat_id, "text": message} 

+

46 response = requests.post(url, params=params, timeout=10) 

+

47 if response.status_code == 200: 

+

48 return True 

+

49 # Log error message 

+

50 LOGGER.error(f"Failed to send telegram notification. Response: {response.text}") 

+

51 return False 

52 

-

53def send(config, last_send=None, dry_run=False): 

-

54 """Send notifications.""" 

-

55 sent_on = None 

-

56 notify_telegram(config=config, last_send=last_send, dry_run=dry_run) 

-

57 email = config_parser.get_smtp_email(config=config) 

-

58 to_email = config_parser.get_smtp_to_email(config=config) 

-

59 host = config_parser.get_smtp_host(config=config) 

-

60 port = config_parser.get_smtp_port(config=config) 

-

61 no_tls = config_parser.get_smtp_no_tls(config=config) 

-

62 username = config_parser.get_smtp_username(config=config) 

-

63 password = config_parser.get_smtp_password(config=config) 

+

53 

+

54def post_message_to_discord(webhook_url, username): 

+

55 """Post message to discord webhook.""" 

+

56 data = {"username": username, "content": MESSAGE_BODY} 

+

57 response = requests.post(webhook_url, data=data, timeout=10) 

+

58 if response.status_code == 204: 

+

59 return True 

+

60 # Log error message 

+

61 LOGGER.error(f"Failed to send telegram notification. Response: {response.text}") 

+

62 return False 

+

63 

64 

-

65 if last_send and last_send > datetime.datetime.now() - datetime.timedelta(hours=24): 

-

66 LOGGER.info("Throttling email to once a day") 

-

67 sent_on = last_send 

-

68 elif email and host and port: 

-

69 try: 

-

70 sent_on = datetime.datetime.now() 

-

71 if not dry_run: 

-

72 smtp = smtplib.SMTP(host, port) 

-

73 smtp.set_debuglevel(0) 

-

74 smtp.connect(host, port) 

-

75 if not no_tls: 

-

76 smtp.starttls() 

-

77 

-

78 if password: 

-

79 if username: 

-

80 smtp.login(username, password) 

-

81 else: 

-

82 smtp.login(email, password) 

-

83 

-

84 msg = build_message(email, to_email) 

+

65def notify_discord(config, last_send=None, dry_run=False): 

+

66 """Send discord notification.""" 

+

67 sent_on = None 

+

68 webhook_url = config_parser.get_discord_webhook_url(config=config) 

+

69 username = config_parser.get_discord_username(config=config) 

+

70 

+

71 if last_send and last_send > datetime.datetime.now() - datetime.timedelta(hours=24): 

+

72 LOGGER.info("Throttling discord to once a day") 

+

73 sent_on = last_send 

+

74 elif webhook_url and username: 

+

75 sent_on = datetime.datetime.now() 

+

76 if not dry_run: 

+

77 # Post message to discord webhook using API 

+

78 if not post_message_to_discord(webhook_url, username): 

+

79 sent_on = None 

+

80 else: 

+

81 LOGGER.warning( 

+

82 "Not sending 2FA notification because Discord is not configured." 

+

83 ) 

+

84 return sent_on 

85 

-

86 smtp.sendmail(from_addr=email, to_addrs=to_email, msg=msg.as_string()) 

-

87 smtp.quit() 

-

88 except Exception as e: 

-

89 sent_on = None 

-

90 LOGGER.error(f"Failed to send email: {str(e)}.") 

-

91 else: 

-

92 LOGGER.warning("Not sending 2FA notification because SMTP is not configured") 

-

93 

-

94 return sent_on 

-

95 

-

96 

-

97def build_message(email, to_email): 

-

98 """Create email message.""" 

-

99 message = Message(to=to_email) 

-

100 message.sender = "icloud-docker <" + email + ">" 

-

101 message.date = datetime.datetime.now().strftime("%d/%m/%Y %H:%M") 

-

102 message.subject = "icloud-docker: Two step authentication required" 

-

103 message.body = """Two-step authentication for iCloud Drive, Photos (Docker) is required. 

-

104Please login to your server and authenticate. Please run - 

-

105`docker exec -it icloud /bin/sh -c "icloud --username=<icloud-username> --session-directory=/app/session_data"`.""" 

-

106 

-

107 return message 

+

86 

+

87def send(config, last_send=None, dry_run=False): 

+

88 """Send notifications.""" 

+

89 sent_on = None 

+

90 notify_telegram(config=config, last_send=last_send, dry_run=dry_run) 

+

91 notify_discord(config=config, last_send=last_send, dry_run=dry_run) 

+

92 email = config_parser.get_smtp_email(config=config) 

+

93 to_email = config_parser.get_smtp_to_email(config=config) 

+

94 host = config_parser.get_smtp_host(config=config) 

+

95 port = config_parser.get_smtp_port(config=config) 

+

96 no_tls = config_parser.get_smtp_no_tls(config=config) 

+

97 username = config_parser.get_smtp_username(config=config) 

+

98 password = config_parser.get_smtp_password(config=config) 

+

99 

+

100 if last_send and last_send > datetime.datetime.now() - datetime.timedelta(hours=24): 

+

101 LOGGER.info("Throttling email to once a day") 

+

102 sent_on = last_send 

+

103 elif email and host and port: 

+

104 try: 

+

105 sent_on = datetime.datetime.now() 

+

106 if not dry_run: 

+

107 smtp = smtplib.SMTP(host, port) 

+

108 smtp.set_debuglevel(0) 

+

109 smtp.connect(host, port) 

+

110 if not no_tls: 

+

111 smtp.starttls() 

+

112 

+

113 if password: 

+

114 if username: 

+

115 smtp.login(username, password) 

+

116 else: 

+

117 smtp.login(email, password) 

+

118 

+

119 msg = build_message(email, to_email) 

+

120 

+

121 smtp.sendmail(from_addr=email, to_addrs=to_email, msg=msg.as_string()) 

+

122 smtp.quit() 

+

123 except Exception as e: 

+

124 sent_on = None 

+

125 LOGGER.error(f"Failed to send email: {str(e)}.") 

+

126 else: 

+

127 LOGGER.warning("Not sending 2FA notification because SMTP is not configured") 

+

128 

+

129 return sent_on 

+

130 

+

131 

+

132def build_message(email, to_email): 

+

133 """Create email message.""" 

+

134 message = Message(to=to_email) 

+

135 message.sender = "icloud-docker <" + email + ">" 

+

136 message.date = datetime.datetime.now().strftime("%d/%m/%Y %H:%M") 

+

137 message.subject = "icloud-docker: Two step authentication required" 

+

138 message.body = """Two-step authentication for iCloud Drive, Photos (Docker) is required. 

+

139Please login to your server and authenticate. Please run - 

+

140`docker exec -it icloud /bin/sh -c "icloud --username=<icloud-username> --session-directory=/app/session_data"`.""" 

+

141 

+

142 return message 

diff --git a/test-coverage/src_sync_drive_py.html b/test-coverage/src_sync_drive_py.html index b709a78eb..7b4a0bb0a 100644 --- a/test-coverage/src_sync_drive_py.html +++ b/test-coverage/src_sync_drive_py.html @@ -406,7 +406,7 @@

« index     coverage.py v5.4, - created at 2024-02-23 16:41 +0000 + created at 2024-02-24 16:06 +0000

diff --git a/test-coverage/src_sync_photos_py.html b/test-coverage/src_sync_photos_py.html index bfa7d4268..3476b0131 100644 --- a/test-coverage/src_sync_photos_py.html +++ b/test-coverage/src_sync_photos_py.html @@ -332,7 +332,7 @@

« index     coverage.py v5.4, - created at 2024-02-23 16:41 +0000 + created at 2024-02-24 16:06 +0000

diff --git a/test-coverage/src_sync_py.html b/test-coverage/src_sync_py.html index 185925c6a..30df0a63b 100644 --- a/test-coverage/src_sync_py.html +++ b/test-coverage/src_sync_py.html @@ -214,7 +214,7 @@

« index     coverage.py v5.4, - created at 2024-02-23 16:41 +0000 + created at 2024-02-24 16:06 +0000

diff --git a/test-coverage/src_usage_py.html b/test-coverage/src_usage_py.html index 55de8742b..9eab8ee5a 100644 --- a/test-coverage/src_usage_py.html +++ b/test-coverage/src_usage_py.html @@ -189,7 +189,7 @@

« index     coverage.py v5.4, - created at 2024-02-23 16:41 +0000 + created at 2024-02-24 16:06 +0000

diff --git a/test-coverage/status.json b/test-coverage/status.json index 948a13bf6..e79b085b0 100644 --- a/test-coverage/status.json +++ b/test-coverage/status.json @@ -1 +1 @@ -{"format":2,"version":"5.4","globals":"39d500336f42ed1e3d49ba0d1ecd0eea","files":{"src___init___py":{"hash":"dccf7a238b1c0ad52f88cf7a87255a24","index":{"nums":[1,77,0,0,0,0,0],"html_filename":"src___init___py.html","relative_filename":"src/__init__.py"}},"src_config_parser_py":{"hash":"4873760913c2aa88e15e2107375840fd","index":{"nums":[1,212,0,0,0,0,0],"html_filename":"src_config_parser_py.html","relative_filename":"src/config_parser.py"}},"src_email_message_py":{"hash":"f1cd58e66273dace4abeac30f6057ce9","index":{"nums":[1,33,0,0,0,0,0],"html_filename":"src_email_message_py.html","relative_filename":"src/email_message.py"}},"src_notify_py":{"hash":"beab8f0a2a9dd62c9b5620ff12a3a0ac","index":{"nums":[1,68,0,0,0,0,0],"html_filename":"src_notify_py.html","relative_filename":"src/notify.py"}},"src_sync_py":{"hash":"f73f24a460564c207536f0df5c9529fa","index":{"nums":[1,81,0,0,0,0,0],"html_filename":"src_sync_py.html","relative_filename":"src/sync.py"}},"src_sync_drive_py":{"hash":"24d38a11e2429df79d2524227f671cc7","index":{"nums":[1,201,0,0,0,0,0],"html_filename":"src_sync_drive_py.html","relative_filename":"src/sync_drive.py"}},"src_sync_photos_py":{"hash":"4c532cd984a51dc8433ef4c99ff3acb1","index":{"nums":[1,112,0,0,0,0,0],"html_filename":"src_sync_photos_py.html","relative_filename":"src/sync_photos.py"}},"src_usage_py":{"hash":"a9d2ca932b8d5f40998bd6aaf25b232d","index":{"nums":[1,86,0,0,0,0,0],"html_filename":"src_usage_py.html","relative_filename":"src/usage.py"}}}} \ No newline at end of file +{"format":2,"version":"5.4","globals":"39d500336f42ed1e3d49ba0d1ecd0eea","files":{"src___init___py":{"hash":"dccf7a238b1c0ad52f88cf7a87255a24","index":{"nums":[1,77,0,0,0,0,0],"html_filename":"src___init___py.html","relative_filename":"src/__init__.py"}},"src_config_parser_py":{"hash":"298d3807682aca9f4e1d615aa59571e6","index":{"nums":[1,226,0,0,0,0,0],"html_filename":"src_config_parser_py.html","relative_filename":"src/config_parser.py"}},"src_email_message_py":{"hash":"f1cd58e66273dace4abeac30f6057ce9","index":{"nums":[1,33,0,0,0,0,0],"html_filename":"src_email_message_py.html","relative_filename":"src/email_message.py"}},"src_notify_py":{"hash":"270819411443a37cb0f22c258888b95f","index":{"nums":[1,91,0,0,0,0,0],"html_filename":"src_notify_py.html","relative_filename":"src/notify.py"}},"src_sync_py":{"hash":"f73f24a460564c207536f0df5c9529fa","index":{"nums":[1,81,0,0,0,0,0],"html_filename":"src_sync_py.html","relative_filename":"src/sync.py"}},"src_sync_drive_py":{"hash":"24d38a11e2429df79d2524227f671cc7","index":{"nums":[1,201,0,0,0,0,0],"html_filename":"src_sync_drive_py.html","relative_filename":"src/sync_drive.py"}},"src_sync_photos_py":{"hash":"4c532cd984a51dc8433ef4c99ff3acb1","index":{"nums":[1,112,0,0,0,0,0],"html_filename":"src_sync_photos_py.html","relative_filename":"src/sync_photos.py"}},"src_usage_py":{"hash":"a9d2ca932b8d5f40998bd6aaf25b232d","index":{"nums":[1,86,0,0,0,0,0],"html_filename":"src_usage_py.html","relative_filename":"src/usage.py"}}}} \ No newline at end of file