tinyzap 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +98 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/tinyzap_manifest.js +1 -0
  6. data/app/assets/stylesheets/tinyzap/application.css +15 -0
  7. data/app/controllers/concerns/tinyzap/open_graph.rb +43 -0
  8. data/app/controllers/tinyzap/application_controller.rb +4 -0
  9. data/app/helpers/tinyzap/application_helper.rb +4 -0
  10. data/app/helpers/tinyzap/open_graph_tag_helper.rb +7 -0
  11. data/app/jobs/tinyzap/application_job.rb +4 -0
  12. data/app/mailers/tinyzap/application_mailer.rb +6 -0
  13. data/app/models/tinyzap/application_record.rb +5 -0
  14. data/app/models/tinyzap/open_graph/base.rb +51 -0
  15. data/app/models/tinyzap/open_graph/image.rb +12 -0
  16. data/app/models/tinyzap/open_graph/metatag.rb +11 -0
  17. data/app/models/tinyzap/open_graph/metatag_mapper.rb +35 -0
  18. data/app/models/tinyzap/open_graph/model.rb +35 -0
  19. data/app/models/tinyzap/open_graph/twitter.rb +11 -0
  20. data/app/views/layouts/tinyzap/application.html.erb +15 -0
  21. data/config/initializers/inflections.rb +3 -0
  22. data/config/initializers/mime_types.rb +3 -0
  23. data/config/routes.rb +2 -0
  24. data/exe/tinyzap +4 -0
  25. data/lib/generators/tinyzap/install/USAGE +11 -0
  26. data/lib/generators/tinyzap/install/install_generator.rb +19 -0
  27. data/lib/generators/tinyzap/install/templates/application.opengraph.erb +15 -0
  28. data/lib/generators/tinyzap/install/templates/tinyzap.rb.tt +14 -0
  29. data/lib/tasks/tinyzap_tasks.rake +4 -0
  30. data/lib/tinyzap/cli.rb +23 -0
  31. data/lib/tinyzap/client.rb +13 -0
  32. data/lib/tinyzap/configuration.rb +18 -0
  33. data/lib/tinyzap/engine.rb +5 -0
  34. data/lib/tinyzap/key_generator.rb +43 -0
  35. data/lib/tinyzap/url_signature.rb +44 -0
  36. data/lib/tinyzap/version.rb +3 -0
  37. data/lib/tinyzap.rb +28 -0
  38. metadata +126 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1accdcd2a97326d9828e08162431229177c9de87f73648bf39df58f36ccaf84e
4
+ data.tar.gz: 1872a8d9330c3a77eba6848ba181b48e6de9285241478b5ba16f5ad4f7eb20aa
5
+ SHA512:
6
+ metadata.gz: ba985f66472361e4c5957d49537f83e4d31e92928888fd6b59b11d47b1d37c16fb93a2beb6f60b5ed028f676173af3bb8f633763d0a0d7b9041d145a4302f04b
7
+ data.tar.gz: e564ae50f51ef060029354f88760412c1777e06c993d1d03003230fcb08d7ab712f1aa92f570df494a6fbc1dcdfd9d829810c0f21a5e914b9892527dbcfde426
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Brad Gessler
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # TinyZap
2
+
3
+ [![Ruby](https://github.com/tinyzap/ruby/actions/workflows/ruby.yml/badge.svg)](https://github.com/tinyzap/ruby/actions/workflows/ruby.yml)
4
+
5
+ The easiest way to make Rails applications look great in Apple Messages, Facebook, LinkedIn, Twitter, and any other website that use Open Graph.
6
+
7
+
8
+ ## Installation
9
+
10
+ From the root of your Rails application, run:
11
+
12
+ ```bash
13
+ $ bundle add "tinyzap"
14
+ ```
15
+
16
+ Then run:
17
+
18
+ ```bash
19
+ $ rails generate tinyzap:install
20
+ ```
21
+
22
+ This creates a `app/views/layout/application.opengraph.erb` file and adds `include TinyZap::OpenGraph` to `ApplicationController`.
23
+
24
+ Add to your `app/views/layouts/application.html.erb` file:
25
+
26
+ ```
27
+ <head>
28
+ <%= opengraph_meta_tags %>
29
+ </head>
30
+ ```
31
+
32
+ That's it for the bare minimum! A screenshot of the top part of the webpage will appear by default for all open graph images. Custom badges are where its at though, so read on my friend.
33
+
34
+ ## Setting OpenGraph data
35
+
36
+ Open graph data can be set from the view or controller via the `opengraph` method.
37
+
38
+ ### Controller
39
+
40
+ Here's a few ways to set opengraph data from a controller.
41
+
42
+ ```ruby
43
+ class PostsController < ApplicationController
44
+ before_action: :assign_opengraph_data
45
+
46
+ def edit
47
+ # This overrides the title that's set from `assign_opengraph_data`
48
+ opengraph.title = "Editing #{@post.title}"
49
+ end
50
+
51
+ protected
52
+
53
+ def assign_opengraph_data
54
+ opengraph.title = @post.title
55
+ opengraph.description = @post.summary
56
+ # Displays the first image of a blog post, instead of a screenshot, for the opengraph image.
57
+ # Assumes the image was managed via ActiveStorage.
58
+ opengraph.image = url_for(@post.images.first)
59
+ end
60
+ end
61
+ ```
62
+
63
+ ### View
64
+
65
+ OpenGraph data may also be set from the view:
66
+
67
+ ```erb
68
+ <%
69
+ opengraph.title = @post.title
70
+ opengraph.description = @post.summary
71
+ %>
72
+
73
+ <h1><%= @post.title %></h1>
74
+ <article><%= @post.body %></article>
75
+ ```
76
+
77
+ ## Custom badges with Rails Views
78
+
79
+ The real power in TinyZap Open Graph is creating custom badges via the `opengraph` format in your rails views. For the example below, we'll create an Open Graph badge for a blog post. Assuming a blog application has a `/posts/:id` with a view at `app/views/posts/show.html.erb`, we'd create a new view with the `opengraph` format:
80
+
81
+ ```bash
82
+ $ touch ./app/views/posts/show.opengraph.erb
83
+ ```
84
+
85
+ Open the file and add something like:
86
+
87
+ ```erb
88
+
89
+ <h1><%= @post.title %></h1>
90
+ <article><%= truncate @post.body, length: 100 %></article>
91
+ <p>This article will take <%= time_to_read @post.body %> minutes to read</p>
92
+ ```
93
+
94
+ The TinyZap screenshot service will take a screenshot of the content at this URL and use it for the Open Graph image.
95
+
96
+ ## License
97
+
98
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/tinyzap .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,43 @@
1
+ module TinyZap
2
+ module OpenGraph
3
+ extend ActiveSupport::Concern
4
+
5
+ DEFAULT_OPENGRAPH_TYPE = "website".freeze
6
+
7
+ DEFAULT_OPENGRAPH_FALLBACK_FORMATS = [ :opengraph, :html ]
8
+ included do
9
+ before_action :assign_opengraph_fallback_formats, if: :opengraph_request?
10
+ before_action :assign_opengraph_defaults
11
+
12
+ helper TinyZap::OpenGraphTagHelper
13
+
14
+ helper_method :opengraph
15
+ end
16
+
17
+ protected
18
+ def assign_opengraph_fallback_formats
19
+ request.formats = DEFAULT_OPENGRAPH_FALLBACK_FORMATS
20
+ end
21
+
22
+ def opengraph_request?
23
+ request.format.opengraph?
24
+ end
25
+
26
+ def url_for_opengraph_image
27
+ tinyzap_opengraph_url url: url_for(format: :opengraph)
28
+ end
29
+
30
+ def tinyzap_opengraph_url(*args, **kwargs)
31
+ TinyZap.client.url_signature.url_for "opengraph", *args, **kwargs
32
+ end
33
+
34
+ def opengraph
35
+ @opengraph ||= Model.new
36
+ end
37
+
38
+ def assign_opengraph_defaults
39
+ opengraph.image ||= url_for_opengraph_image
40
+ opengraph.type ||= DEFAULT_OPENGRAPH_TYPE
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,4 @@
1
+ module TinyZap
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module TinyZap
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module TinyZap
2
+ module OpenGraphTagHelper
3
+ def opengraph_meta_tags(model=opengraph)
4
+ model.to_html
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ module TinyZap
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module TinyZap
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module TinyZap
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,51 @@
1
+ module TinyZap
2
+ module OpenGraph
3
+ # Provides a way to specify OpenGraph keys for an OpenGraphModel, which can later
4
+ # be iterated upon to generate OpenGraph meta tags.
5
+ class Base
6
+ # Encapsulates OpenGraph properties and provides helpers that are
7
+ # useful for documentation purposes or for reflecting on Ruby objects.
8
+ class Property
9
+ attr_accessor :key, :name, :description, :default
10
+
11
+ def initialize(key, description = nil, default: nil)
12
+ @key = key
13
+ @description = description
14
+ # If we get a string like `og:image:url`, this would give us `url`
15
+ *_, @name = key.rpartition(":")
16
+ @default = default
17
+ end
18
+ end
19
+
20
+ # Allows for the object to be initialized with args like `Image.new(url: "https://example.com/logo.png", alt: "Logo image")`.
21
+ def initialize(**kwargs)
22
+ kwargs.each do |kwarg, value|
23
+ self.send("#{kwarg}=", value)
24
+ rescue NoMethodError
25
+ raise NoMethodError, "#{kwarg.inspect} is not a property of #{self.inspect}"
26
+ end
27
+ end
28
+
29
+ # DSL for creating properties when defining a model.
30
+ def self.property(*args, **kwargs)
31
+ property = Property.new *args, **kwargs
32
+ attr_accessor property.name
33
+ self.properties.append property
34
+ end
35
+
36
+ # Array where properties are registered.
37
+ def self.properties
38
+ @properties ||= []
39
+ end
40
+
41
+ # Iterates through the properties and also gets their value.
42
+ def properties
43
+ Enumerator.new do |y|
44
+ self.class.properties.each do |property|
45
+ y << [ property, (self.send(property.name) || property.default) ]
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,12 @@
1
+ module TinyZap
2
+ module OpenGraph
3
+ class Image < Base
4
+ property "og:image:url", "Identical to og:image."
5
+ property "og:image:secure_url", "An alternate url to use if the webpage requires HTTPS."
6
+ property "og:image:type", "A MIME type for this image."
7
+ property "og:image:width", "The number of pixels wide."
8
+ property "og:image:height", "The number of pixels high."
9
+ property "og:image:alt", "A description of what is in the image (not a caption). If the page specifies an og:image it should specify og:image:alt."
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module TinyZap
2
+ module OpenGraph
3
+ class Metatag < Struct.new(:property, :content)
4
+ include ActionView::Helpers::TagHelper
5
+
6
+ def to_html
7
+ tag :meta, property: property, content: content
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,35 @@
1
+ module TinyZap
2
+ module OpenGraph
3
+ # Iterates recursively through an OpenGraph object and gets a bunch of
4
+ # metatags and keys.
5
+ class MetatagMapper
6
+ include ActionView::Helpers::OutputSafetyHelper
7
+
8
+ attr_reader :model
9
+ delegate :context,
10
+ to: :model
11
+
12
+ def initialize(model)
13
+ @model = model
14
+ end
15
+
16
+ def metatags
17
+ Enumerator.new do |y|
18
+ model.properties.each do |property, content|
19
+ if content.respond_to? :properties
20
+ MetatagMapper.new(content).metatags.each do |tag|
21
+ y << tag
22
+ end
23
+ else
24
+ y << Metatag.new(property.key, content) if content.present?
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def to_html
31
+ safe_join metatags.map(&:to_html), "\n"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ module TinyZap
2
+ module OpenGraph
3
+ class Model < Base
4
+ property "og:title", %[The title of your object as it should appear within the graph, e.g., "The Rock".]
5
+ property "og:type", %[The type of your object, e.g., "video.movie". Depending on the type you specify, other properties may also be required.]
6
+ property "og:image", %[An image URL which should represent your object within the graph.]
7
+ property "og:url", %[The canonical URL of your object that will be used as its permanent ID in the graph, e.g., "https://www.imdb.com/title/tt0117500/".]
8
+ property "og:description", %[A one to two sentence description of your object.]
9
+ property "twitter", %[A one to two sentence description of your object.]
10
+
11
+ delegate :to_html, to: :metatag_mapper
12
+
13
+ def image
14
+ @image ||= Image.new
15
+ end
16
+
17
+ def image=(url)
18
+ image.url = url
19
+ end
20
+
21
+ def twitter
22
+ @twitter ||= Twitter.new.tap do |twitter|
23
+ twitter.title = title
24
+ twitter.description = description
25
+ twitter.image = image.url
26
+ end
27
+ end
28
+
29
+ private
30
+ def metatag_mapper
31
+ MetatagMapper.new(self)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ module TinyZap
2
+ module OpenGraph
3
+ class Twitter < Base
4
+ property "twitter:card", "Type of card, which is 'summary_large_image'", default: "summary_large_image"
5
+ property "twitter:site", "Twitter @handle of the account"
6
+ property "twitter:title", "Title of the card, similar to og:title"
7
+ property "twitter:description", "Description of the card, similar to og:description"
8
+ property "twitter:image", "Image URL of the card, similar to og:image"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>TinyZap</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "tinyzap/application", media: "all" %>
9
+ </head>
10
+ <body>
11
+
12
+ <%= yield %>
13
+
14
+ </body>
15
+ </html>
@@ -0,0 +1,3 @@
1
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
2
+ inflect.acronym "TinyZap"
3
+ end
@@ -0,0 +1,3 @@
1
+ # Used to represent the HTML pages that will be converted into an
2
+ # image and served up for open graph image previews.
3
+ Mime::Type.register_alias "text/html", :opengraph
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ TinyZap::Engine.routes.draw do
2
+ end
data/exe/tinyzap ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require "tinyzap"
3
+
4
+ TinyZap::CLI.start ARGV
@@ -0,0 +1,11 @@
1
+ Description:
2
+ Installs TinyZap in Rails
3
+
4
+ Example:
5
+ bin/rails generate install:tinyzap
6
+
7
+ Creates the files:
8
+ app/views/layouts/application.opengraph.html
9
+
10
+ Patches ApplicationController by adding:
11
+ include TinyZap::OpenGraph
@@ -0,0 +1,19 @@
1
+ class TinyZap::InstallGenerator < Rails::Generators::Base
2
+ source_root File.expand_path("templates", __dir__)
3
+
4
+ def include_controller_helper
5
+ inject_into_file 'app/controllers/application_controller.rb', after: "class ApplicationController < ActionController::Base\n" do <<-'RUBY'
6
+ include TinyZap::OpenGraph
7
+
8
+ RUBY
9
+ end
10
+ end
11
+
12
+ def copy_layout
13
+ copy_file "application.opengraph.erb", "app/views/layouts/application.opengraph.erb"
14
+ end
15
+
16
+ def copy_configuration_file
17
+ template "tinyzap.rb.tt", "config/initializers/tinyzap.rb"
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= opengraph.title %></title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
8
+
9
+ <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
10
+ <%= javascript_importmap_tags %>
11
+ </head>
12
+ <body>
13
+ <%= yield %>
14
+ </body>
15
+ </html>
@@ -0,0 +1,14 @@
1
+ TinyZap.configure do |config|
2
+ if Rails.env.production?
3
+ # For production deployments, set the following environment keys:
4
+ #
5
+ # ```
6
+ # TINYZAP_SECRET_KEY=
7
+ # TINYZAP_PUBLIC_KEY=
8
+ # ```
9
+ config.load_env
10
+ else
11
+ config.secret_key = "<%= TinyZap.key_generator.secret_key %>"
12
+ config.public_key = "<%= TinyZap.key_generator.public_key %>"
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :tinyzap do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,23 @@
1
+ require "thor"
2
+
3
+ module TinyZap
4
+ class CLI < Thor
5
+ include Thor::Actions
6
+
7
+ desc "install", "Install TinyZap to the Rails application"
8
+ def install
9
+ run "./bin/bundle add tinyzap"
10
+ run "./bin/rails generate tinyzap:install"
11
+ end
12
+
13
+ desc "version", "Prints the version of tinyzap"
14
+ def version
15
+ puts TinyZap::VERSION
16
+ end
17
+
18
+ desc "environment [ENVIRONMENT]", "Generates environment variables for target enrivonment"
19
+ def environment(environment = TinyZap::KeyGenerator::ENVIRONMENT)
20
+ puts TinyZap.key_generator(environment: environment).env_vars
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module TinyZap
2
+ class Client
3
+ delegate :secret_key, :public_key, to: :configuration
4
+
5
+ def url_signature
6
+ @url_signature ||= UrlSignature.new(secret_key: secret_key, public_key: public_key)
7
+ end
8
+
9
+ def configuration
10
+ @configuration ||= Configuration.new
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module TinyZap
2
+ class Configuration
3
+ attr_accessor :secret_key, :public_key
4
+
5
+ def load_secret_key_env
6
+ self.secret_key = ENV["TINYZAP_SECRET_KEY"]
7
+ end
8
+
9
+ def load_public_key_env
10
+ self.public_key = ENV["TINYZAP_PUBLIC_KEY"]
11
+ end
12
+
13
+ def load_env
14
+ load_secret_key_env
15
+ load_public_key_env
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ module TinyZap
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace TinyZap
4
+ end
5
+ end
@@ -0,0 +1,43 @@
1
+ require "securerandom"
2
+
3
+ module TinyZap
4
+ # Generates random keys for environments.
5
+ class KeyGenerator
6
+ LENGTH = 14
7
+ DELIMITER = "_".freeze
8
+ ENVIRONMENT = :development
9
+
10
+ attr_reader :environment
11
+
12
+ def initialize(environment: ENVIRONMENT)
13
+ @environment = environment
14
+ end
15
+
16
+ def public_key
17
+ generate :public
18
+ end
19
+
20
+ def secret_key
21
+ generate :secret
22
+ end
23
+
24
+ def env_vars
25
+ <<~ENVARS
26
+ TINYZAP_SECRET_KEY=#{secret_key}
27
+ TINYZAP_PUBLIC_KEY=#{public_key}
28
+ ENVARS
29
+ end
30
+
31
+ def generate(*scopes)
32
+ scopes
33
+ .prepend(environment)
34
+ .append(random)
35
+ .join(DELIMITER)
36
+ end
37
+
38
+ private
39
+ def random
40
+ SecureRandom.hex(LENGTH)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,44 @@
1
+ require "openssl"
2
+ require "uri"
3
+
4
+ module TinyZap
5
+ class UrlSignature
6
+ # Use for `OpenSSL::HMAC`
7
+ DIGEST = "SHA256".freeze
8
+
9
+ attr_reader :secret_key, :public_key, :path_prefix
10
+
11
+ def initialize(secret_key:, public_key:)
12
+ @secret_key = secret_key
13
+ @public_key = public_key
14
+ @path_prefix = File.join("/", "v1", public_key)
15
+ end
16
+
17
+ def signed_url(path)
18
+ URI.join("https://tinyzap.com/", signed_path(path))
19
+ end
20
+
21
+ def valid?(url)
22
+ path = URI(url).request_uri
23
+ version, account_key, signature, path = Regexp.new("/(v1)/(.+?)/(.+?)(/.+)").match(path).captures
24
+ signature == sign(path)
25
+ end
26
+
27
+ def url_for(path, **query)
28
+ path = URI(path).tap do |url|
29
+ url.path = path
30
+ url.query = query.to_query
31
+ end
32
+ signed_url path
33
+ end
34
+
35
+ private
36
+ def signed_path(path)
37
+ File.join(path_prefix, sign(File.join("/", path.to_s)), path.to_s)
38
+ end
39
+
40
+ def sign(data)
41
+ OpenSSL::HMAC.hexdigest(DIGEST, secret_key, data)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module TinyZap
2
+ VERSION = "0.1.4"
3
+ end
data/lib/tinyzap.rb ADDED
@@ -0,0 +1,28 @@
1
+ require "tinyzap/version"
2
+ require "tinyzap/engine" if defined? Rails
3
+ require "zeitwerk"
4
+
5
+ module TinyZap
6
+ Loader = Zeitwerk::Loader.for_gem.tap do |loader|
7
+ loader.ignore "#{__dir__}/generators"
8
+ loader.inflector.inflect(
9
+ "tinyzap" => "TinyZap",
10
+ "cli" => "CLI"
11
+ )
12
+ loader.setup
13
+ end
14
+
15
+ class << self
16
+ def client
17
+ @client ||= Client.new
18
+ end
19
+
20
+ def key_generator(environment: Rails.env)
21
+ @key_generator ||= KeyGenerator.new(environment: environment)
22
+ end
23
+
24
+ def configure(&block)
25
+ block.call client.configuration
26
+ end
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tinyzap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Brad Gessler
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-11-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 7.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 7.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: zeitwerk
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.5'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.5'
55
+ description: Easiest way to generate fresh images for Rails applications.
56
+ email:
57
+ - brad@tinyzap.com
58
+ executables:
59
+ - tinyzap
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - MIT-LICENSE
64
+ - README.md
65
+ - Rakefile
66
+ - app/assets/config/tinyzap_manifest.js
67
+ - app/assets/stylesheets/tinyzap/application.css
68
+ - app/controllers/concerns/tinyzap/open_graph.rb
69
+ - app/controllers/tinyzap/application_controller.rb
70
+ - app/helpers/tinyzap/application_helper.rb
71
+ - app/helpers/tinyzap/open_graph_tag_helper.rb
72
+ - app/jobs/tinyzap/application_job.rb
73
+ - app/mailers/tinyzap/application_mailer.rb
74
+ - app/models/tinyzap/application_record.rb
75
+ - app/models/tinyzap/open_graph/base.rb
76
+ - app/models/tinyzap/open_graph/image.rb
77
+ - app/models/tinyzap/open_graph/metatag.rb
78
+ - app/models/tinyzap/open_graph/metatag_mapper.rb
79
+ - app/models/tinyzap/open_graph/model.rb
80
+ - app/models/tinyzap/open_graph/twitter.rb
81
+ - app/views/layouts/tinyzap/application.html.erb
82
+ - config/initializers/inflections.rb
83
+ - config/initializers/mime_types.rb
84
+ - config/routes.rb
85
+ - exe/tinyzap
86
+ - lib/generators/tinyzap/install/USAGE
87
+ - lib/generators/tinyzap/install/install_generator.rb
88
+ - lib/generators/tinyzap/install/templates/application.opengraph.erb
89
+ - lib/generators/tinyzap/install/templates/tinyzap.rb.tt
90
+ - lib/tasks/tinyzap_tasks.rake
91
+ - lib/tinyzap.rb
92
+ - lib/tinyzap/cli.rb
93
+ - lib/tinyzap/client.rb
94
+ - lib/tinyzap/configuration.rb
95
+ - lib/tinyzap/engine.rb
96
+ - lib/tinyzap/key_generator.rb
97
+ - lib/tinyzap/url_signature.rb
98
+ - lib/tinyzap/version.rb
99
+ homepage: https://tinyzap.com/
100
+ licenses:
101
+ - MIT
102
+ metadata:
103
+ allowed_push_host: https://rubygems.org/
104
+ homepage_uri: https://tinyzap.com/
105
+ source_code_uri: https://github.com/tinyzap/ruby
106
+ changelog_uri: https://github.com/tinyzap/ruby/releases
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubygems_version: 3.4.6
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: Easiest way to generate fresh images for Rails applications.
126
+ test_files: []