#StackBounty: #ruby-on-rails #ubuntu #ssl #nginx #lets-encrypt example.com redirected you too many times. ERR_TOO_MANY_REDIRECTS

Bounty: 50

I was trying to Secure Nginx with Let’s Encrypt on Ubuntu 16.04.

example.conf file before obtaining an SSL Certificate

server {
    server_name example.com www.example.com ;
    # Tell Nginx and Passenger where your app's 'public' directory is
    root /var/www/backup/mycode/public;
    # Turn on Passenger
    passenger_enabled on;
    rails_env development;
    passenger_ruby /usr/local/rvm/gems/ruby-2.5.6/wrappers/ruby;

}

http://example.com/ is working fine.

I try to Obtain an SSL Certificate by

sudo certbot --nginx -d example.com -d www.example.com

the result was

Your existing certificate has been successfully renewed, and the new certificate
has been installed.

The new certificate covers the following domains: https://example.com and
https://www.example.com

example.conf file after obtaining an SSL Certificate

server {
    server_name example.com www.example.com ;
    # Tell Nginx and Passenger where your app's 'public' directory is
    root /var/www/backup/example.com/public;
    # Turn on Passenger
    passenger_enabled on;
    rails_env development;
    passenger_ruby /usr/local/rvm/gems/ruby-2.5.6/wrappers/ruby;




    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = www.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    server_name example.com www.example.com ;
    listen 80;
    return 404; # managed by Certbot

}

http://example.com/ is redirecting to https://example.com/ too many times

example.com redirected you too many times.
ERR_TOO_MANY_REDIRECTS

  1. Why is it redirecting too many times?
  2. what is the purpose of the second server block?
    server {
    if ($host = www.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    
    
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    
    
    server_name example.com www.example.com ;
    listen 80;
    return 404; # managed by Certbot
    
     }
    
  3. How to make all redirects to https://www.example.com/ ?

EDIT1

Moving the certibot managed code to second server block has stopped the too many redirects problem. But my website is back again directing to HTTP instead of https.

    server {
            server_name example.com www.example.com ;
            # Tell Nginx and Passenger where your app's 'public' directory is
            root /var/www/backup/example.com/public;
            # Turn on Passenger
            passenger_enabled on;
            rails_env development;
            passenger_ruby /usr/local/rvm/gems/ruby-2.5.6/wrappers/ruby;

        }
        server {

            listen 443 ssl; # managed by Certbot
            ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
            ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
            include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
            ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
            if ($host = www.example.com) {
                return 301 https://$host$request_uri;
            } # managed by Certbot


            if ($host = example.com) {
                return 301 https://$host$request_uri;
            } # managed by Certbot


            server_name example.com www.example.com ;
            listen 80;
            return 404; # managed by Certbot

        }


Get this bounty!!!

#StackBounty: #ruby-on-rails #ruby #google-sheets #google-drive-api Iterating Through Rows when importing Gsheet Worksheets Via Ruby Ge…

Bounty: 100

I’m using the "google_drive" gem to access a Google Sheet worksheet and I’ve been able to access and print the worksheet, so the API connection is fine.

However, I’m trying to build a method that iterates through every row and find or creates a user based on that. I’ve tried these two options:


def import
      session = GoogleDrive::Session.from_service_account_key("credspath")
      spreadsheet  = session.spreadsheet_by_title("My Worksheet Title")
      worksheet  = spreadsheet.worksheets.first
      worksheet.rows.each do |row|
        customer = Customer.find_by(email: row['email'])
        if customer.blank?
           customer = Customer.new(email: row['email'] )
           puts "New Customer #{customer.email} "
        end
      end
    end

and this


def import
      session = GoogleDrive::Session.from_service_account_key("credspath")
      spreadsheet  = session.spreadsheet_by_title("My Worksheet Title")
      worksheet  = spreadsheet.worksheets.first
      CSV.foreach(worksheet, headers: true, encoding:"iso-8859-1:utf-8") do |row|
        customer = Customer.find_by(email: row['email'])
        if customer.blank?
           customer = Customer.new(email: row['email'] )
           puts "New Customer #{customer.email} "
        end
      end
    end

I’m getting the error: "no implicit conversion of String into Integer" for the line that the iteration starts on…

How can I create from this API connection WITHOUT exporting to CSV?


Get this bounty!!!

#StackBounty: #ruby-on-rails #regex #ruby #validation #bcrypt BCrypt-3.1.11 hashed passwords suddenly have endless stream of xoo chara…

Bounty: 50

I recently started getting BCrypt “invalid hash” errors when I tried to save a record with a password, so I looked into the BCrypt code, and found the following method for validating passwords:

  def valid_hash?(h)
    h =~ /^$[0-9a-z]{2}$[0-9]{2}$[A-Za-z0-9./]{53}$/
  end

which is called by the initialize method:

def initialize(raw_hash)
  if valid_hash?(raw_hash)
    self.replace(raw_hash)
    @version, @cost, @salt, @checksum = split_hash(self)
  else
    raise Errors::InvalidHash.new("invalid hash")
  end
end

The following passwords:

"PassiveForbearenceFox"
"VindictivePurpleAlligator12345"
"LostBlueLizard!@#$1234" 

all return Invalid Hash errors.

UPDATE:

I dug deeper, and found that the regex is checking the hashed password, but the hash that is getting passed for some reason has an endless stream of /x00s after it. For example, if I type in the password “LostBlueLizard!@#1234”, the hash that is passed to challenge the regex is

"$2a$11$NcmldbbyCDfumGYALgYhfuIQt2FZ8gpbVCQfuiVlwjhCtkD2ndDFyx00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00..... and so on, for farther than I could scroll.

If I remove the x00s and just pass in $2a$11$NcmldbbyCDfumGYALgYhfuIQt2FZ8gpbVCQfuiVlwjhCtkD2ndDFy, it passes the regex.

Does anyone have any idea why the hash has those characters? I can’t prove they weren’t there before, but my passwords always were accepted until recently.

UPDATE 2:

Also, it’s actually the raw_hash that’s getting input into the initialize method that’s the hash with all the x00s. So somewhere there’s code that generates the faulty hash and passes it to initialize, but I searched the entire gem’s codebase for the term “initialize” and there were no results like that, so I can’t find where the hash is actually generated.

UPDATE 3:

Okay I tracked the issue further, to the BCrypt::Engine.create method, which calls the __bc_crypt method, which is what returns the faulty hash. But __bc_crypt is actually from a file called “ext/mri/bcrypt_ext.c” and is written in C, which I think is beyond my ability to investigate.

I simply updated BCrypt from 3.1.11 to 3.1.13, and now it works fine. I’m not sure whether it was a bug or not, but the point is it works now.


Get this bounty!!!

#StackBounty: #ruby-on-rails #session #nginx #load-balancing #round-robin Nginx config changes for sticky session in round robin

Bounty: 100

Rails application(4.2) is hosted on nginx and serves at localhost:5478. The ip_hash in the code snippet below maintains the server request response consistency and works as expected.

upstream rails {
  ip_hash;

To share the load, ip_hash was commented. Now the login for the user starts failing since passing of session cookie is required while works in similar way for Rails3. This is related to something around sticky session but unable to trace the exact way of handling it.

nginx.conf

upstream mongrel {
    server 127.0.0.1:5469;
  }

  upstream rails {
    #ip_hash;
    server 127.0.0.1:5479;
    server 127.0.0.1:5480;
    server 127.0.0.1:5481;
    server 127.0.0.1:5482;
  }


    location / {
      # Setup redirection headers
      proxy_set_header   X-Real-IP         $remote_addr;
      proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
      proxy_set_header   Host              $http_host;

      # Pass the request thru
      proxy_pass         http://mongrel;
    }
  }

  server {
    listen          5478 default;
    server_name     _;
    root            "../games/public";

    location ~ ^/assets/ {
      root "../d2/public";
      expires 1y;
      add_header Cache-Control public;

      add_header ETag "";
      break;
    }

I tried using consistent_hash $scheme $request_uri;
as suggested but consistent_hash as a directive is not recognized and fails. Let me know if any config change is required for nginx. I also found the same nginx config with ip_hash commented works for Rails3 application, not sure if this is related


Get this bounty!!!

#StackBounty: #ruby-on-rails #activerecord #arel matches_any throws exception on empty array writing custom filter for Datatables using…

Bounty: 100

I have am working with Ruby on Rails using the ajax-datatables-rails gem for datatables for which I need a custom filter.

My current filter looks like this:

def filter_status_column
  statuses = []
  ->(column, value) do
    # Do stuff and put statuses in the array
    ::Arel::Nodes::SqlLiteral.new(column.field.to_s).matches_any(statuses)
  end
end

This, when my array is not empty will generate some sql like this:

0> ::Arel::Nodes::SqlLiteral.new(column.field.to_s).matches_any(like_mapped_values).to_sql
=> "(status ILIKE 'Foo' OR status ILIKE 'Bar')"

If the array this causes an exception which my expectation is after running .where("status in ?", []) against the model is like this as that turns [] to null:

"(status ILIKE NULL)"

Calling

::Arel::Nodes::SqlLiteral.new(column.field.to_s).matches_any([]).to_sql

generates the error

Unsupported argument type: NilClass. Construct an Arel node instead.

What is the correct method to handle an empty array in matches_any? I could also do this without arel I suppose as well. Status is just a column on a model

EDIT: Further background, this datatable on the UI side has a search box and this field differs in text between what’s displayed and what’s actually in the database. This custom filter takes the distinct values from the database and maps the view text to the meaningful database text. It “likes” the viewed text, takes the match from the database side, and needs to apply filters as it goes. So, a partial match on the view text is matched to the actual database match. This means there could be no database matches and match_any? pukes on that.


Get this bounty!!!

#StackBounty: #ruby-on-rails #postgresql #activerecord Get the latest child messages and also parent messages that are childless

Bounty: 100

The following is the Message model

class Message < ApplicationRecord
  belongs_to :parent_message, class_name: 'Message', optional: true
  has_many :child_messages, foreign_key: :parent_message_id, class_name: "Message"
  has_many :message_participants

  scope :latest_messages_by_participant, -> (user_id) do
    select("DISTINCT ON (parent_message_id) messages.*").
        joins(:message_participants).
        where(message_participants: { user_id: user_id }).
        order("parent_message_id, created_at DESC")
  end
end

message_participants has a record for each message and the various people who have sent or received that message. It has a user_id on it.

The problem with the above latest_messages_by_participant scope is that it is able to get all the child messages BUT it gets only the last parent message. That is because we are calling DISINTICT ON on parent_message_id, and for childless parent messages this value is NULL and so it’s just calling distinct on NULL and returns on 1 value (the last childless parent message).

How can I fetch all the latest messages including the latest child messages AND the latest childless parent message in a single query?

I’m using Rails 6 and Postgres 11.

P.S: I should also point out a secondary problem which is that the messages are returned in created_at ASC. The created_at DESC is able to get the latest child message but does not sort the overall collection. I can solve this by calling .reverse, but wondering if there was a way to fix that as well.


Get this bounty!!!

#StackBounty: #ruby-on-rails #docker #ssh #docker-compose #ssh-agent ssh-agent forwarding into docker-compose environment is not working

Bounty: 100

I have been having serious troubles to get ssh-agent forwarded into the docker container (with my docker-compose installation). I have Mac running Catalina, with docker-engine 19.03.8 and Compose @ 1.24.
The following is my docker-compose file:

version: '3.7'
services:
  platform:
    build:
      context: .
      dockerfile: ./platform/compose/Dockerfile.platform.local
    working_dir: /root/platform
    ports:
      - "3000:3000"
    command: ["./compose/scripts/start_rails.sh"]
    tty: true
    stdin_open: true
    volumes:
      - type: bind
        source: /run/host-services/ssh-auth.sock
        target: /run/host-services/ssh-auth.sock
    env_file: ./platform/.env
    environment:
      TERM: xterm-256color
      SSH_AUTH_SOCK: /run/host-services/ssh-auth.sock

volumes:

The way I have configured ssh-agent forwarding is as specified in docker-compose documentation

The ./compose/scripts/start_rails.sh script does bundle install && bundle exec rails s. I have few gems that I am pulling from private-repositories and I thought I should be able to install these gems by forwarding ssh-agent.

I have also tried starting the ssh-agent before I spin the docker-compose up, but that doesnt seem to do anything.

{
  "debug": true,
  "experimental": true,
  "features": {
    "buildkit": true
  }
}

This is what I have added inside my docker configuration file. Any help is appreciated.

UPDATE:

The following in my .ssh directory structure and config:

tree ~/.ssh

├── config
├── known_hosts
├── midhun
│   ├── id_rsa
│   └── id_rsa.pub
└── client
    ├── id_rsa
    └── id_rsa.pub

cat ~/.ssh/config

Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/client/id_rsa

Host me.github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/midhun/id_rsa


Get this bounty!!!

#StackBounty: #ruby-on-rails #ruby #rmagick Display a converted PDF to a rails page

Bounty: 50

So I was checking on how to display PDF thumbnails in Rails since for some reason creating a thumbnail version of my file in my uploader doesn’t work, and it lead me to this:
Convert a .doc or .pdf to an image and display a thumbnail in Ruby?

So I got up to this:

def show_thumbnail
    require 'rmagick'
    pdf = Magick::ImageList.new(self.pdf_file.file.path)
    first_page = pdf.first
    scaled_page = first_page.scale(300, 450)
end 

But how do I display scaled_page to a webpage?

I added this function in the decorator so I can do something like this:

= image_tag(pdf.pdf_file.show_thumbnail)

But it results in this error:

Can't resolve image into URL: undefined method `to_model' for #<Magick::Image:0x0000000122c4b300>


Get this bounty!!!

#StackBounty: #ruby-on-rails #google-chrome Chrome Rails Session's Cookie Change Random Times

Bounty: 50

I’m on Rails 3.2.22.5 for one of my apps. After the Chrome v80 update, started to experience sessions expiring way before the default expire. So after doing inspect watching, I noticed the cookie id assigned for the session_store changes randomly.

I noticed these values for the session:

HttpOnly: true
Secure: null
SameSite:  null

Would these be related to my issue?


Get this bounty!!!

#StackBounty: #ruby-on-rails #api #swagger #rswag How create with rswag following the json api specification?

Bounty: 50

I didn’t find any examples of how to use rswag to generate documentation according to json api.

spec/integration/pets_spec.rb

require ‘swagger_helper’

It is possible to change the code to generate the format of json api?

describe 'Pets API' do

  path '/api/v1/pets' do

    post 'Creates a pet' do
      tags 'Pets'
      consumes 'application/json', 'application/xml'
      parameter name: :pet, in: :body, schema: {
        type: :object,
        properties: {
          name: { type: :string },
          photo_url: { type: :string },
          status: { type: :string }
        },
        required: [ 'name', 'status' ]
      }

      response '201', 'pet created' do
        let(:pet) { { name: 'Dodo', status: 'available' } }
        run_test!
      end

      response '422', 'invalid request' do
        let(:pet) { { name: 'foo' } }
        run_test!
      end
    end
  end

  path '/api/v1/pets/{id}' do

    get 'Retrieves a pet' do
      tags 'Pets'
      produces 'application/json', 'application/xml'
      parameter name: :id, :in => :path, :type => :string

      response '200', 'name found' do
        schema type: :object,
          properties: {
            id: { type: :integer, },
            name: { type: :string },
            photo_url: { type: :string },
            status: { type: :string }
          },
          required: [ 'id', 'name', 'status' ]

        let(:id) { Pet.create(name: 'foo', status: 'bar', photo_url: 'http://example.com/avatar.jpg').id }
        run_test!
      end

      response '404', 'pet not found' do
        let(:id) { 'invalid' }
        run_test!
      end
    end
  end
end

If rswag what tips would you give me?


Get this bounty!!!