fuck_facebook 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8034fd3f3afb91d27f11300b42e15e07c92808c473daec3459f82c14ab772ff6
4
- data.tar.gz: f656f97d23da62a99d618ec197ddf8f3b9f3d8c818d71ed16d27cb35b8d25123
3
+ metadata.gz: 9f15615d0c24e530547c2a40e4509d434bc25578dde17737a5b8d8ef5fe2e68f
4
+ data.tar.gz: e3c8a9d379b9df92d0d986bfb1dba35846779d32d4cf1bbf16ae39d1f778fae4
5
5
  SHA512:
6
- metadata.gz: afc81df11373573a7ce572a09574f7c5159f278f3173a924202b1f0f11cd913922f89caaac117901eca27c4634576180733050da46f839c2b714b40ce4d8b068
7
- data.tar.gz: 97e1f728a14dd6f67af0985a2d382753579fd160c16866b85946e19d855d15ec2c8ed9ed24d921cdddde2c2064e76541a145abac090360bd2670bec57f15cf82
6
+ metadata.gz: cffa79b7c7b58717a8507ba129668db846b40e6682621527b7799665d4fa74a5032a27ef471da20659ee01cd57662e82d85f76aff5b01e43a547d638e0c70374
7
+ data.tar.gz: 4acc110f1bb5e7115b28a429594a5fc8459f402fcffe88391a7189687791d677e857117049227d656d977c00b5daac88b4bded2780b1044b81fdce8cc603f0e6
data/.gitignore CHANGED
@@ -9,3 +9,5 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+
13
+ *.gem
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.0.1
1
+ 3.0.2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,4 @@
1
- ## [Unreleased]
2
-
3
1
  ## [0.1.0] - 2021-07-15
4
2
 
3
+ - Send unread messages to your email address
5
4
  - Initial release
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,23 @@
1
+ # Developer Guide
2
+
3
+ ## Pushing a new version of the gem
4
+
5
+ **Note:** You must have been granted access to deploy new versions of the `fuck_facebook` gem
6
+
7
+ * Bump the version in `lib/fuck_facebook/version.rb`
8
+ * Build the gem with `gem build fuck_facebook.gemspec`
9
+ * Push the gem with `gem push fuck_facebook-VERSION.gem` replacing `VERSION` with the new version number
10
+
11
+ ## Pushing a new version of the Docker image
12
+
13
+ **Note:** You must have been granted access to deploy new versions of the `fuck_facebook` Docker image
14
+
15
+ * Build the image:
16
+
17
+ ```
18
+ docker build . -t keeyan/fuck_facebook:VERSION --build-arg version=VERSION
19
+ ```
20
+
21
+ Replace `VERSION` with the version number
22
+
23
+ * Push the image with `docker push keeyan/fuck_facebook:VERSION` replacing `VERSION` with the version number
data/Dockerfile ADDED
@@ -0,0 +1,15 @@
1
+ FROM ruby:3.0.2-bullseye
2
+
3
+ RUN apt-get update && apt-get install -y chromium-driver
4
+
5
+ RUN useradd --create-home --shell /bin/bash fuckfacebook
6
+
7
+ USER fuckfacebook
8
+ WORKDIR /home/fuckfacebook
9
+
10
+ RUN mkdir -p /home/fuckfacebook/.local/share/fuck-facebook
11
+ VOLUME /home/fuckfacebook/.local/share/fuck-facebook
12
+
13
+ ARG version
14
+ COPY fuck_facebook-$version.gem .
15
+ RUN gem install fuck_facebook-$version.gem
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fuck_facebook (0.1.0)
4
+ fuck_facebook (0.2.1)
5
5
  activesupport (~> 6.1)
6
6
  highline (~> 2.0)
7
7
  mail (~> 2.7)
@@ -10,7 +10,7 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- activesupport (6.1.4)
13
+ activesupport (6.1.4.4)
14
14
  concurrent-ruby (~> 1.0, >= 1.0.2)
15
15
  i18n (>= 1.6, < 2)
16
16
  minitest (>= 5.1)
@@ -21,13 +21,13 @@ GEM
21
21
  coderay (1.1.3)
22
22
  concurrent-ruby (1.1.9)
23
23
  highline (2.0.3)
24
- i18n (1.8.10)
24
+ i18n (1.8.11)
25
25
  concurrent-ruby (~> 1.0)
26
26
  mail (2.7.1)
27
27
  mini_mime (>= 0.1.1)
28
28
  method_source (1.0.0)
29
- mini_mime (1.1.0)
30
- minitest (5.14.4)
29
+ mini_mime (1.1.2)
30
+ minitest (5.15.0)
31
31
  parallel (1.20.1)
32
32
  parser (3.0.1.1)
33
33
  ast (~> 2.4.1)
@@ -56,7 +56,7 @@ GEM
56
56
  tzinfo (2.0.4)
57
57
  concurrent-ruby (~> 1.0)
58
58
  unicode-display_width (2.0.0)
59
- zeitwerk (2.4.2)
59
+ zeitwerk (2.5.1)
60
60
 
61
61
  PLATFORMS
62
62
  ruby
@@ -67,4 +67,4 @@ DEPENDENCIES
67
67
  rubocop
68
68
 
69
69
  BUNDLED WITH
70
- 2.2.15
70
+ 2.2.22
data/README.md CHANGED
@@ -1,3 +1,46 @@
1
1
  # Fuck Facebook
2
2
 
3
3
  A collection of tools to help you use Facebook when you don't want to
4
+
5
+ ## Usage
6
+
7
+ Run `fuck-facebook --help` to get a list of options and explanations.
8
+
9
+ To get all unread messages (that haven't already been reported) run these commands:
10
+
11
+ ```
12
+ fuck-facebook --login
13
+ ```
14
+
15
+ You only need to login once
16
+
17
+ ```
18
+ fuck-facebook --unread-messages
19
+ ```
20
+
21
+ This will only show you unread messages that have been received since the last time you checked.
22
+ This way if you have emails going out for new messages, you won't get notified for the same message each time.
23
+
24
+ ## Config
25
+
26
+ Here's a complete config file along with an explanation of each option:
27
+
28
+ ```yaml
29
+ smtp:
30
+ from_email: sender@example.com
31
+ to_email: receiver@example.com
32
+ address: smtp.example.com
33
+ port: 587
34
+ user_name: some_user_name
35
+ password: 123456
36
+ authentication: plain
37
+ ```
38
+
39
+ These options can be passed as environment variables, by:
40
+ * Joining the keys with `_`
41
+ * Capitalizing the entire string
42
+ * Prefixing the key with `FF_`
43
+
44
+ For example the `smtp` `from_email` will become `FF_SMTP_FROM_EMAIL`
45
+
46
+ Environment variables take precedent over the config file.
data/bin/fuck-facebook CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'optparse'
4
4
  require 'mail'
5
- require 'pry'
6
5
 
7
6
  require_relative '../src/facebook_connection'
8
7
  require_relative '../src/config'
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  DESCRIPTION
14
14
  spec.homepage = 'https://gitlab.com/keeyan/fuck_facebook'
15
15
  spec.license = 'MIT'
16
- spec.required_ruby_version = Gem::Requirement.new('>= 3.0.1')
16
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0', '< 3.1')
17
17
 
18
18
  spec.metadata['allowed_push_host'] = 'https://rubygems.org'
19
19
 
@@ -1,3 +1,3 @@
1
1
  module FuckFacebook
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
  end
data/src/authenticator.rb CHANGED
@@ -19,7 +19,7 @@ class Authenticator
19
19
 
20
20
  accept_cookies
21
21
  submit_credentials
22
- submit_2fa
22
+ submit_otp
23
23
  click_remember_password
24
24
  end
25
25
 
@@ -32,7 +32,7 @@ class Authenticator
32
32
 
33
33
  def click_remember_password
34
34
  driver.navigate.to('https://www.facebook.com/settings?tab=security')
35
- driver.switch_to.frame(xpaths.element(:settings, :security_iframe))
35
+ driver.switch_to.frame(xpaths.wait_for_element(:settings, :security_iframe))
36
36
  xpaths.element(:settings, :save_login_information_edit_button).click
37
37
  xpaths.element(:settings, :save_login_information_button).click
38
38
  end
@@ -43,15 +43,20 @@ class Authenticator
43
43
  xpaths.element(:login_button).click
44
44
  end
45
45
 
46
- def submit_2fa
47
- return unless xpaths.element(:checkpoint, :prompt).text == 'Two-factor authentication required'
46
+ def submit_otp
47
+ return unless xpaths.element_exists?(:checkpoint, :otp_prompt)
48
48
 
49
49
  xpaths.element(:checkpoint, :otp_input).send_keys(user_input.get(:otp))
50
- xpaths.element(:checkpoint, :otp_continue_button).click
51
- xpaths.element(:checkpoint, :save_browser_continue_button).click
50
+ otp_button = xpaths.element(:checkpoint, :submit_button)
51
+ otp_button.click
52
+
53
+ save_browser_button = xpaths.element(:checkpoint, :submit_button)
54
+ save_browser_button.click
52
55
  end
53
56
 
54
57
  def accept_cookies
58
+ return unless xpaths.element_exists?(:accept_cookies_button)
59
+
55
60
  accept_cookies_button = xpaths.element(:accept_cookies_button)
56
61
  accept_cookies_button.click
57
62
  end
data/src/config.rb CHANGED
@@ -1,9 +1,27 @@
1
1
  require 'yaml'
2
2
 
3
3
  class Config
4
- CONFIG = YAML.load_file("#{ENV['HOME']}/.config/fuck-facebook/config.yaml", symbolize_names: true)
4
+ CONFIG_FILE_PATH = "#{ENV['HOME']}/.local/share/fuck-facebook/config.yaml".freeze
5
5
 
6
6
  def self.option(*path)
7
- CONFIG.dig(*path)
7
+ env_var = "FF_#{path.join('_').upcase}"
8
+ return ENV[env_var] if ENV[env_var]
9
+
10
+ path_strings = path.map(&:to_s)
11
+ config.dig(*path_strings)
12
+ end
13
+
14
+ private
15
+
16
+ def self.config
17
+ create_config_file_if_not_exists!
18
+
19
+ YAML.load_file(CONFIG_FILE_PATH)
20
+ end
21
+
22
+ def self.create_config_file_if_not_exists!
23
+ dirname = File.dirname(CONFIG_FILE_PATH)
24
+ FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
25
+ File.write(CONFIG_FILE_PATH, '{}') unless File.exist?(CONFIG_FILE_PATH)
8
26
  end
9
27
  end
@@ -41,7 +41,7 @@ class CookieHandler
41
41
  saved_cookies = JSON.parse(File.read(cookies_filename), symbolize_names: true)
42
42
 
43
43
  saved_cookies.each do |saved_cookie|
44
- saved_cookie[:expires] = Time.parse(saved_cookie[:expires])
44
+ saved_cookie[:expires] = Time.parse(saved_cookie[:expires]) unless saved_cookie[:expires].nil?
45
45
  end
46
46
 
47
47
  saved_cookies
@@ -31,6 +31,8 @@ class FacebookConnection
31
31
 
32
32
  options = Selenium::WebDriver::Chrome::Options.new
33
33
  options.add_argument('--disable-notifications')
34
+ options.add_argument('--no-sandbox')
35
+ options.add_argument('--disable-dev-shm-usage')
34
36
  options.add_argument('--headless') if headless
35
37
  options.add_option('detach', true) unless headless
36
38
 
@@ -18,10 +18,7 @@ class MessageHandler
18
18
  def messages
19
19
  visit_messages_page
20
20
 
21
- xpaths.wait_for_element(:messages, :chats)
22
-
23
- chats = xpaths.elements(:messages, :chats)
24
-
21
+ chats = xpaths.wait_for_elements(:messages, :chats)
25
22
  messages = messages_for_chats(chats)
26
23
 
27
24
  messages_after_last_message_time(messages)
@@ -32,15 +29,29 @@ class MessageHandler
32
29
  def messages_for_chats(chats)
33
30
  chats.map do |chat|
34
31
  message_thread = MessageThread.new(title: xpaths.child_element(chat, :messages, :title_relative).text)
35
- text = xpaths.child_element(chat, :messages, :text_relative).text
36
- read = !xpaths.element_has_child?(chat, :messages, :mark_as_read_button_relative)
37
- message_time_ago = xpaths.child_element(chat, :messages, :time_sent_ago_relative).text
38
- timestamp = FbDuration.parse_to_time(message_time_ago)
39
32
 
40
- Message.new(message_thread: message_thread, text: text, read: read, timestamp: timestamp)
33
+ Message.new(
34
+ message_thread: message_thread,
35
+ text: chat_text(chat),
36
+ read: chat_read?(chat),
37
+ timestamp: chat_timestamp(chat)
38
+ )
41
39
  end
42
40
  end
43
41
 
42
+ def chat_text(chat)
43
+ xpaths.child_element(chat, :messages, :text_relative).text
44
+ end
45
+
46
+ def chat_read?(chat)
47
+ !xpaths.element_has_child?(chat, :messages, :mark_as_read_button_relative)
48
+ end
49
+
50
+ def chat_timestamp(chat)
51
+ message_time_ago = xpaths.child_element(chat, :messages, :time_sent_ago_relative).text
52
+ FbDuration.parse_to_time(message_time_ago)
53
+ end
54
+
44
55
  def messages_after_last_message_time(messages)
45
56
  last_message_time = Storage.get(:last_message_time, default: Time.new(2004, 2, 4))
46
57
 
data/src/storage.rb CHANGED
@@ -29,7 +29,7 @@ class Storage
29
29
  def self.storage
30
30
  create_storage_file_if_not_exists!
31
31
 
32
- YAML.load_file(STORAGE_FILE_PATH, symbolize_names: true)
32
+ YAML.load_file(STORAGE_FILE_PATH)
33
33
  end
34
34
 
35
35
  def self.create_storage_file_if_not_exists!
data/src/xpaths.rb CHANGED
@@ -63,17 +63,24 @@ class Xpaths
63
63
  found_element
64
64
  end
65
65
 
66
+ def wait_for_elements(*path_elements)
67
+ wait_for_element(*path_elements)
68
+
69
+ elements(*path_elements)
70
+ end
71
+
66
72
  def for(*path_elements)
67
- result = XPATHS.dig(*path_elements)
73
+ path_elements_strings = path_elements.map(&:to_s)
74
+ result = XPATHS.dig(*path_elements_strings)
68
75
 
69
- raise 'Could not find xpath' if result.empty?
76
+ raise 'Could not find xpath' if result.nil? || result.empty?
70
77
 
71
78
  result
72
79
  end
73
80
 
74
81
  private_class_method def self.xpaths_from_file
75
82
  xpaths_file = File.join(File.dirname(__FILE__), '../xpaths.yaml')
76
- YAML.load_file(xpaths_file, symbolize_names: true)
83
+ YAML.load_file(xpaths_file)
77
84
  end
78
85
 
79
86
  XPATHS = xpaths_from_file
data/xpaths.yaml CHANGED
@@ -8,13 +8,12 @@ settings:
8
8
  save_login_information_button: '//div[text() = "Save your login information"]'
9
9
  link_to_profile: '//a[@href="/me/"]'
10
10
  checkpoint:
11
- otp_input: '/html/body/div[1]/div[3]/div[1]/div/form/div/div[2]/div[3]/span/input'
12
- otp_continue_button: '/html/body/div[1]/div[3]/div[1]/div/form/div/div[3]/div[1]/button'
11
+ otp_prompt: '//strong[text() = "Two-factor authentication required"]'
12
+ otp_input: '//*[@id="approvals_code"]'
13
13
  save_browser_radio_input: '/html/body/div[1]/div[3]/div[1]/div/form/div/div[2]/div[2]/div[1]/input'
14
- save_browser_continue_button: '/html/body/div[1]/div[3]/div[1]/div/form/div/div[3]/div[1]/button'
15
- prompt: '/html/body/div[1]/div[3]/div[1]/div/form/div/div[1]'
14
+ submit_button: '//*[@id="checkpointSubmitButton"]'
16
15
  messages:
17
- chats: '/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div/div/div[3]/div[1]/div[2]/div/child::*[@role = "row"]'
16
+ chats: './/*[@aria-label="Chats"]/child::*'
18
17
  title_relative: 'div[1]/div/a/div/div[2]/div[1]/div/div/div[1]/span/span/span/span'
19
18
  text_relative: 'div[1]/div/a/div/div[2]/div[1]/div/div/div[2]/span/span/div/span[1]/span'
20
19
  time_sent_ago_relative: 'div[1]/div/a/div/div[2]/div[1]/div/div/div[2]/span/span/div/span[3]'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fuck_facebook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keeyan Nejad
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-15 00:00:00.000000000 Z
11
+ date: 2021-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -81,6 +81,8 @@ files:
81
81
  - ".rubocop.yml"
82
82
  - ".ruby-version"
83
83
  - CHANGELOG.md
84
+ - CONTRIBUTING.md
85
+ - Dockerfile
84
86
  - Gemfile
85
87
  - Gemfile.lock
86
88
  - LICENSE.txt
@@ -125,14 +127,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
125
127
  requirements:
126
128
  - - ">="
127
129
  - !ruby/object:Gem::Version
128
- version: 3.0.1
130
+ version: 2.7.0
131
+ - - "<"
132
+ - !ruby/object:Gem::Version
133
+ version: '3.1'
129
134
  required_rubygems_version: !ruby/object:Gem::Requirement
130
135
  requirements:
131
136
  - - ">="
132
137
  - !ruby/object:Gem::Version
133
138
  version: '0'
134
139
  requirements: []
135
- rubygems_version: 3.2.15
140
+ rubygems_version: 3.2.22
136
141
  signing_key:
137
142
  specification_version: 4
138
143
  summary: A collection of tools to help you use Facebook when you don't want to