login con imap
This commit is contained in:
parent
3bc2bfed3c
commit
6a1240308d
18 changed files with 290 additions and 70 deletions
12
Gemfile
12
Gemfile
|
@ -29,9 +29,14 @@ gem 'jbuilder', '~> 2.5'
|
|||
# Use Capistrano for deployment
|
||||
# gem 'capistrano-rails', group: :development
|
||||
|
||||
gem 'email_address'
|
||||
gem 'rails_warden'
|
||||
gem 'haml-rails'
|
||||
gem 'bootstrap', '~> 4.0.0.beta3'
|
||||
gem 'jekyll'
|
||||
|
||||
group :development, :test do
|
||||
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
|
||||
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
|
||||
gem 'pry'
|
||||
# Adds support for Capybara system testing and selenium driver
|
||||
gem 'capybara', '~> 2.13'
|
||||
gem 'selenium-webdriver'
|
||||
|
@ -45,6 +50,3 @@ group :development do
|
|||
gem 'spring'
|
||||
gem 'spring-watcher-listen', '~> 2.0.0'
|
||||
end
|
||||
|
||||
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
||||
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
|
||||
|
|
79
Gemfile.lock
79
Gemfile.lock
|
@ -41,9 +41,14 @@ GEM
|
|||
addressable (2.5.2)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
arel (8.0.0)
|
||||
autoprefixer-rails (7.2.4)
|
||||
execjs
|
||||
bindex (0.5.0)
|
||||
bootstrap (4.0.0.beta3)
|
||||
autoprefixer-rails (>= 6.0.3)
|
||||
popper_js (>= 1.12.3, < 2)
|
||||
sass (>= 3.5.2)
|
||||
builder (3.2.3)
|
||||
byebug (9.1.0)
|
||||
capybara (2.16.1)
|
||||
addressable
|
||||
mini_mime (>= 0.1.3)
|
||||
|
@ -53,18 +58,63 @@ GEM
|
|||
xpath (~> 2.0)
|
||||
childprocess (0.8.0)
|
||||
ffi (~> 1.0, >= 1.0.11)
|
||||
coderay (1.1.2)
|
||||
colorator (1.1.0)
|
||||
concurrent-ruby (1.0.5)
|
||||
crass (1.0.3)
|
||||
em-websocket (0.5.1)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
email_address (0.1.6)
|
||||
netaddr
|
||||
simpleidn
|
||||
erubi (1.7.0)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.2.5)
|
||||
execjs (2.7.0)
|
||||
ffi (1.9.18)
|
||||
forwardable-extended (2.6.0)
|
||||
globalid (0.4.1)
|
||||
activesupport (>= 4.2.0)
|
||||
haml (5.0.4)
|
||||
temple (>= 0.8.0)
|
||||
tilt
|
||||
haml-rails (1.0.0)
|
||||
actionpack (>= 4.0.1)
|
||||
activesupport (>= 4.0.1)
|
||||
haml (>= 4.0.6, < 6.0)
|
||||
html2haml (>= 1.0.1)
|
||||
railties (>= 4.0.1)
|
||||
html2haml (2.2.0)
|
||||
erubis (~> 2.7.0)
|
||||
haml (>= 4.0, < 6)
|
||||
nokogiri (>= 1.6.0)
|
||||
ruby_parser (~> 3.5)
|
||||
http_parser.rb (0.6.0)
|
||||
i18n (0.9.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jbuilder (2.7.0)
|
||||
activesupport (>= 4.2.0)
|
||||
multi_json (>= 1.2)
|
||||
jekyll (3.7.0)
|
||||
addressable (~> 2.4)
|
||||
colorator (~> 1.0)
|
||||
em-websocket (~> 0.5)
|
||||
i18n (~> 0.7)
|
||||
jekyll-sass-converter (~> 1.0)
|
||||
jekyll-watch (~> 2.0)
|
||||
kramdown (~> 1.14)
|
||||
liquid (~> 4.0)
|
||||
mercenary (~> 0.3.3)
|
||||
pathutil (~> 0.9)
|
||||
rouge (>= 1.7, < 4)
|
||||
safe_yaml (~> 1.0)
|
||||
jekyll-sass-converter (1.5.1)
|
||||
sass (~> 3.4)
|
||||
jekyll-watch (2.0.0)
|
||||
listen (~> 3.0)
|
||||
kramdown (1.16.2)
|
||||
liquid (4.0.0)
|
||||
listen (3.1.5)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
|
@ -74,14 +124,22 @@ GEM
|
|||
nokogiri (>= 1.5.9)
|
||||
mail (2.7.0)
|
||||
mini_mime (>= 0.1.1)
|
||||
mercenary (0.3.6)
|
||||
method_source (0.9.0)
|
||||
mini_mime (1.0.0)
|
||||
mini_portile2 (2.3.0)
|
||||
minitest (5.10.3)
|
||||
multi_json (1.12.2)
|
||||
netaddr (1.5.1)
|
||||
nio4r (2.1.0)
|
||||
nokogiri (1.8.1)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
pathutil (0.16.1)
|
||||
forwardable-extended (~> 2.6)
|
||||
popper_js (1.12.9)
|
||||
pry (0.11.3)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.9.0)
|
||||
public_suffix (3.0.1)
|
||||
puma (3.11.0)
|
||||
rack (2.0.3)
|
||||
|
@ -104,6 +162,8 @@ GEM
|
|||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
loofah (~> 2.0)
|
||||
rails_warden (0.5.8)
|
||||
warden (>= 1.0.0)
|
||||
railties (5.1.4)
|
||||
actionpack (= 5.1.4)
|
||||
activesupport (= 5.1.4)
|
||||
|
@ -114,8 +174,12 @@ GEM
|
|||
rb-fsevent (0.10.2)
|
||||
rb-inotify (0.9.10)
|
||||
ffi (>= 0.5.0, < 2)
|
||||
rouge (3.1.0)
|
||||
ruby_dep (1.5.0)
|
||||
ruby_parser (3.10.1)
|
||||
sexp_processor (~> 4.9)
|
||||
rubyzip (1.2.1)
|
||||
safe_yaml (1.0.4)
|
||||
sass (3.5.4)
|
||||
sass-listen (~> 4.0.0)
|
||||
sass-listen (4.0.0)
|
||||
|
@ -130,6 +194,8 @@ GEM
|
|||
selenium-webdriver (3.8.0)
|
||||
childprocess (~> 0.5)
|
||||
rubyzip (~> 1.0)
|
||||
sexp_processor (4.10.0)
|
||||
simpleidn (0.0.9)
|
||||
spring (2.0.2)
|
||||
activesupport (>= 4.2)
|
||||
spring-watcher-listen (2.0.1)
|
||||
|
@ -143,6 +209,7 @@ GEM
|
|||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
sqlite3 (1.3.13)
|
||||
temple (0.8.0)
|
||||
thor (0.20.0)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.8)
|
||||
|
@ -153,6 +220,8 @@ GEM
|
|||
thread_safe (~> 0.1)
|
||||
uglifier (4.1.2)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
warden (1.2.7)
|
||||
rack (>= 1.0)
|
||||
web-console (3.5.1)
|
||||
actionview (>= 5.0)
|
||||
activemodel (>= 5.0)
|
||||
|
@ -168,19 +237,23 @@ PLATFORMS
|
|||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
byebug
|
||||
bootstrap (~> 4.0.0.beta3)
|
||||
capybara (~> 2.13)
|
||||
email_address
|
||||
haml-rails
|
||||
jbuilder (~> 2.5)
|
||||
jekyll
|
||||
listen (>= 3.0.5, < 3.2)
|
||||
pry
|
||||
puma (~> 3.7)
|
||||
rails (~> 5.1.4)
|
||||
rails_warden
|
||||
sass-rails (~> 5.0)
|
||||
selenium-webdriver
|
||||
spring
|
||||
spring-watcher-listen (~> 2.0.0)
|
||||
sqlite3
|
||||
turbolinks (~> 5)
|
||||
tzinfo-data
|
||||
uglifier (>= 1.3.0)
|
||||
web-console (>= 3.3.0)
|
||||
|
||||
|
|
BIN
app/assets/images/background.jpg
Normal file
BIN
app/assets/images/background.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
||||
* listed below.
|
||||
*
|
||||
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
|
||||
* vendor/assets/stylesheets directory can be referenced here using a relative path.
|
||||
*
|
||||
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
||||
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
||||
* files in this directory. Styles in this file should be added after the last require_* statement.
|
||||
* It is generally better to create a new file per style scope.
|
||||
*
|
||||
*= require_tree .
|
||||
*= require_self
|
||||
*/
|
38
app/assets/stylesheets/application.scss
Normal file
38
app/assets/stylesheets/application.scss
Normal file
|
@ -0,0 +1,38 @@
|
|||
@import "bootstrap";
|
||||
|
||||
$footer-height: 60px;
|
||||
|
||||
.background-cover {
|
||||
background: image-url("background.jpg") no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.full-height {
|
||||
height: calc(100vh - #{$footer-height});
|
||||
}
|
||||
|
||||
html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-bottom: $footer-height;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: $footer-height;
|
||||
line-height: $footer-height;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
textarea.post-content {
|
||||
min-height: 80vh;
|
||||
font-family: monospace;
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
class ApplicationController < ActionController::Base
|
||||
protect_from_forgery with: :exception
|
||||
|
||||
def index
|
||||
redirect_to sites_path
|
||||
end
|
||||
end
|
||||
|
|
21
app/controllers/login_controller.rb
Normal file
21
app/controllers/login_controller.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
class LoginController < ApplicationController
|
||||
protect_from_forgery with: :exception
|
||||
|
||||
def index
|
||||
redirect_to new_login_path
|
||||
end
|
||||
|
||||
def new
|
||||
@has_cover = true
|
||||
render 'login/new'
|
||||
end
|
||||
|
||||
def create
|
||||
authenticate
|
||||
|
||||
if authenticated?
|
||||
# TODO enviar a la URL de donde vinimos
|
||||
redirect_to sites_path
|
||||
end
|
||||
end
|
||||
end
|
6
app/controllers/sites_controller.rb
Normal file
6
app/controllers/sites_controller.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
class SitesController < ApplicationController
|
||||
before_action :authenticate!
|
||||
|
||||
def index
|
||||
end
|
||||
end
|
18
app/models/usuaria.rb
Normal file
18
app/models/usuaria.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Un modelo para la usuaria que no se corresponde con una base de datos
|
||||
# porque vienen de IMAP
|
||||
#
|
||||
# Una usuaria puede tener muchos sitios, pero no podemos establecer
|
||||
# relaciones estilo has_many porque no estamos usando ActiveRecord, que
|
||||
# requeriría que guardemos todo en una base de datos.
|
||||
class Usuaria < OpenStruct
|
||||
# Crear una usuaria ad hoc, porque la base de datos de usuarias está
|
||||
# en otro lado.
|
||||
def self.find(username)
|
||||
Usuaria.new(username: username)
|
||||
end
|
||||
|
||||
# Obtener todos los sitios de esta usuaria
|
||||
def sites
|
||||
@sites ||= Site.all_for(self)
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Sutty</title>
|
||||
<%= csrf_meta_tags %>
|
||||
|
||||
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
|
||||
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%= yield %>
|
||||
</body>
|
||||
</html>
|
15
app/views/layouts/application.html.haml
Normal file
15
app/views/layouts/application.html.haml
Normal file
|
@ -0,0 +1,15 @@
|
|||
!!!
|
||||
%html
|
||||
%head
|
||||
%meta{content: "text/html; charset=UTF-8", 'http-equiv': "Content-Type"}/
|
||||
%title Sutty
|
||||
= csrf_meta_tags
|
||||
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
|
||||
%body{class: @has_cover ? 'background-cover' : ''}
|
||||
.container-fluid
|
||||
= yield
|
||||
%footer.footer
|
||||
%p{style: @has_cover ? 'color: white' : ''}
|
||||
%a{href: 'https://0xacab.org/itacate-kefir/sutty'} Sutty
|
||||
es desarrollada por
|
||||
%a{href: 'https://kefir.red'} Kéfir
|
14
app/views/login/new.haml
Normal file
14
app/views/login/new.haml
Normal file
|
@ -0,0 +1,14 @@
|
|||
.row.align-items-center.justify-content-center.full-height
|
||||
.col-md-6.align-self-center
|
||||
- if flash[:error]
|
||||
.alert.alert-danger{role: 'alert'}
|
||||
= flash[:error]
|
||||
|
||||
= form_tag login_path do
|
||||
.form-group
|
||||
%input{type: 'email', name: 'username', class: 'form-control', placeholder: t('login.email')}
|
||||
.form-group
|
||||
%input{type: 'password', name: 'password', class: 'form-control', placeholder: t('login.password')}
|
||||
|
||||
.form-group
|
||||
%input{type: 'submit', value: t('login.submit', class: 'btn btn-lg btn-primary btn-block'}
|
1
app/views/sites/index.haml
Normal file
1
app/views/sites/index.haml
Normal file
|
@ -0,0 +1 @@
|
|||
%h1= t('sites.title')
|
18
config/initializers/warden.rb
Normal file
18
config/initializers/warden.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
require 'warden/imap'
|
||||
|
||||
Rails.configuration.middleware.use RailsWarden::Manager do |manager|
|
||||
manager.default_strategies :imap
|
||||
manager.failure_app = -> (env) { LoginController.action(:new).call(env) }
|
||||
end
|
||||
|
||||
class Warden::SessionSerializer
|
||||
def serialize(record)
|
||||
[record.username]
|
||||
end
|
||||
|
||||
def deserialize(keys)
|
||||
Usuaria.find(keys.first)
|
||||
end
|
||||
end
|
||||
|
||||
Warden::Strategies.add(:imap, Warden::IMAP::Strategy)
|
|
@ -1,33 +1,7 @@
|
|||
# Files in the config/locales directory are used for internationalization
|
||||
# and are automatically loaded by Rails. If you want to use locales other
|
||||
# than English, add the necessary files in this directory.
|
||||
#
|
||||
# To use the locales, use `I18n.t`:
|
||||
#
|
||||
# I18n.t 'hello'
|
||||
#
|
||||
# In views, this is aliased to just `t`:
|
||||
#
|
||||
# <%= t('hello') %>
|
||||
#
|
||||
# To use a different locale, set it with `I18n.locale`:
|
||||
#
|
||||
# I18n.locale = :es
|
||||
#
|
||||
# This would use the information in config/locales/es.yml.
|
||||
#
|
||||
# The following keys must be escaped otherwise they will not be retrieved by
|
||||
# the default I18n backend:
|
||||
#
|
||||
# true, false, on, off, yes, no
|
||||
#
|
||||
# Instead, surround them with single quotes.
|
||||
#
|
||||
# en:
|
||||
# 'true': 'foo'
|
||||
#
|
||||
# To learn more, please read the Rails Internationalization guide
|
||||
# available at http://guides.rubyonrails.org/i18n.html.
|
||||
|
||||
en:
|
||||
hello: "Hello world"
|
||||
login:
|
||||
email: 'E-mail'
|
||||
password: 'Password'
|
||||
submit: 'Log in'
|
||||
sites:
|
||||
title: 'Sites'
|
||||
|
|
7
config/locales/es.yml
Normal file
7
config/locales/es.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
es:
|
||||
login:
|
||||
email: 'Dirección de correo'
|
||||
password: 'Contraseña'
|
||||
submit: 'Ingresar'
|
||||
sites:
|
||||
title: 'Sitios'
|
|
@ -1,3 +1,10 @@
|
|||
Rails.application.routes.draw do
|
||||
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
|
||||
root 'application#index'
|
||||
|
||||
get 'login/new', to: 'login#new'
|
||||
post 'login', to: 'login#create'
|
||||
|
||||
resources :sites do
|
||||
resources :posts
|
||||
end
|
||||
end
|
||||
|
|
51
lib/warden/imap.rb
Normal file
51
lib/warden/imap.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'net/imap'
|
||||
require 'warden'
|
||||
require 'email_address'
|
||||
|
||||
module Warden
|
||||
module IMAP
|
||||
# Una estrategia de autenticación por IMAP
|
||||
class Strategy < Warden::Strategies::Base
|
||||
def valid?
|
||||
return false unless params.include? 'username'
|
||||
return false unless params.include? 'password'
|
||||
|
||||
@email = EmailAddress.new(params['username'])
|
||||
|
||||
@email.valid?
|
||||
end
|
||||
|
||||
def authenticate!
|
||||
imap_connect
|
||||
imap_login
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def imap_connect
|
||||
# No vamos a enviar la contraseña en texto plano a ningún lado
|
||||
@imap = Net::IMAP.new(@email.host_name, ssl: true)
|
||||
# Errores más comunes según
|
||||
# https://ruby-doc.org/stdlib-2.0.0/libdoc/net/imap/rdoc/Net/IMAP.html
|
||||
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, Errno::ENETUNREACH,
|
||||
SocketError, Net::IMAP::ByeResponseError => e
|
||||
|
||||
@imap.disconnect
|
||||
fail! e.to_s
|
||||
end
|
||||
|
||||
def imap_login
|
||||
@imap.login(@email.normal, params['password'])
|
||||
@imap.disconnect
|
||||
|
||||
success! Usuaria.find(@email.normal)
|
||||
rescue EOFError => e
|
||||
@imap.disconnect
|
||||
fail! e.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in a new issue