Skip to content

Commit c2b03bf

Browse files
committed
Merge branch 'release/0.1.1'
2 parents 972bb36 + 965d61f commit c2b03bf

File tree

10 files changed

+62
-44
lines changed

10 files changed

+62
-44
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## v0.1.1
4+
5+
* Encode the username in Base64 in the authentication cookie to allow it
6+
contains dots
7+
38
## v0.1.0
49

510
* Login store specification

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![hex.pm version](http://img.shields.io/hexpm/v/expected.svg?style=flat)](https://hex.pm/packages/expected)
44

5-
Expected is an Elixir module for login and session management. It enables
5+
Expected is an Elixir application for login and session management. It enables
66
persistent logins through a cookie, following Barry Jaspan’s
77
[Improved Persistent Login Cookie Best Practice](http://www.jaspan.com/improved_persistent_login_cookie_best_practice).
88
It also provides an API to list and discard sessions.
@@ -12,7 +12,7 @@ It also provides an API to list and discard sessions.
1212
To use Expected in your app, add this to your dependencies:
1313

1414
```elixir
15-
{:expected, "~> 0.1.0"}
15+
{:expected, "~> 0.1.1"}
1616
```
1717

1818
### Configuration

lib/expected.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,9 @@ defmodule Expected do
537537
defp put_auth_cookie(conn, login) do
538538
auth_cookie_name = conn.private.expected.auth_cookie
539539
max_age = conn.private.expected.cookie_max_age
540-
auth_cookie = "#{login.username}.#{login.serial}.#{login.token}"
540+
541+
auth_cookie =
542+
"#{Base.encode64(login.username)}.#{login.serial}.#{login.token}"
541543

542544
put_resp_cookie(conn, auth_cookie_name, auth_cookie, max_age: max_age)
543545
end

lib/expected/plugs.ex

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,11 @@ defmodule Expected.Plugs do
243243
{:ok, String.t(), String.t(), String.t()}
244244
| {:error, :invalid}
245245
defp parse_auth_cookie(auth_cookie) when is_binary(auth_cookie) do
246-
case String.split(auth_cookie, ".") do
247-
[user, serial, token] ->
248-
{:ok, user, serial, token}
249-
250-
_ ->
251-
{:error, :invalid}
246+
with [encoded_user, serial, token] <- String.split(auth_cookie, "."),
247+
{:ok, user} <- Base.decode64(encoded_user) do
248+
{:ok, user, serial, token}
249+
else
250+
_ -> {:error, :invalid}
252251
end
253252
end
254253

mix.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Expected.Mixfile do
22
use Mix.Project
33

4-
@version "0.1.0"
4+
@version "0.1.1"
55
@repo_url "https://github.com/ejpcmac/expected"
66

77
def project do
@@ -29,7 +29,7 @@ defmodule Expected.Mixfile do
2929
source_ref: "v#{@version}"
3030
],
3131
package: package(),
32-
description: "An Elixir module for login and session management."
32+
description: "An Elixir application for login and session management."
3333
]
3434
end
3535

mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"ex_unit_notifier": {:hex, :ex_unit_notifier, "0.1.4", "36a2dcab829f506e01bf17816590680dd1474407926d43e64c1263e627c364b8", [:mix], [], "hexpm"},
99
"excoveralls": {:hex, :excoveralls, "0.8.0", "99d2691d3edf8612f128be3f9869c4d44b91c67cec92186ce49470ae7a7404cf", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
1010
"exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm"},
11-
"export_private": {:hex, :export_private, "1.0.0", "b5c312653fb6343aa97a0ccdd52bd975efc2934eb84c5d935c71a55beb8061ce", [], [], "hexpm"},
11+
"export_private": {:hex, :export_private, "1.0.0", "b5c312653fb6343aa97a0ccdd52bd975efc2934eb84c5d935c71a55beb8061ce", [:mix], [], "hexpm"},
1212
"fs": {:hex, :fs, "0.9.2", "ed17036c26c3f70ac49781ed9220a50c36775c6ca2cf8182d123b6566e49ec59", [:rebar], [], "hexpm"},
1313
"hackney": {:hex, :hackney, "1.10.1", "c38d0ca52ea80254936a32c45bb7eb414e7a96a521b4ce76d00a69753b157f21", [:rebar3], [{:certifi, "2.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
1414
"idna": {:hex, :idna, "5.1.0", "d72b4effeb324ad5da3cab1767cb16b17939004e789d8c0ad5b70f3cea20c89a", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},

test/expected/cleaner_test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ defmodule Expected.CleanerTest do
2727
# Wait for the cleaning to trigger.
2828
Process.sleep(1100)
2929

30-
assert MemoryStore.list_user_logins("user", @server) == [@login]
30+
assert MemoryStore.list_user_logins(@username, @server) == [@login]
3131
end
3232

3333
test "does not trigger login cleaning before timeout" do
@@ -38,7 +38,7 @@ defmodule Expected.CleanerTest do
3838
# Wait a millisecond to let the cleaner start.
3939
Process.sleep(1)
4040

41-
assert MemoryStore.list_user_logins("user", @server) == [
41+
assert MemoryStore.list_user_logins(@username, @server) == [
4242
@login,
4343
@old_login
4444
]

test/expected/plugs_test.exs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ defmodule Expected.PlugsTest do
1818
table: @ets_table
1919
]
2020

21-
@not_loaded_user %NotLoadedUser{username: "user"}
22-
@auth_cookie_content "user.serial.token"
21+
@not_loaded_user %NotLoadedUser{username: @username}
22+
23+
@encoded_username Base.encode64(@username)
24+
@auth_cookie_content "#{@encoded_username}.#{@serial}.#{@token}"
25+
@no_login_cookie "#{Base.encode64("some_user")}.some_serial.some_token"
26+
@bad_token_cookie "#{@encoded_username}.#{@serial}.bad_token"
2327

2428
setup do
2529
setup_stores()
@@ -82,7 +86,9 @@ defmodule Expected.PlugsTest do
8286
|> send_resp(:ok, "")
8387

8488
assert [%Login{} = login] = MemoryStore.list_user_logins("user", @server)
85-
assert conn.cookies[@auth_cookie] == "user.#{login.serial}.#{login.token}"
89+
90+
assert conn.cookies[@auth_cookie] ==
91+
"#{Base.encode64(login.username)}.#{login.serial}.#{login.token}"
8692
end
8793

8894
## Configuration
@@ -263,14 +269,16 @@ defmodule Expected.PlugsTest do
263269
|> authenticate()
264270
|> send_resp(:ok, "")
265271

266-
[login] = MemoryStore.list_user_logins("user", @server)
272+
[login] = MemoryStore.list_user_logins(@username, @server)
267273

268-
assert login.serial == @login.serial
269-
assert login.token != @login.token
270-
assert login.sid != @login.sid
274+
assert login.serial == @serial
275+
assert login.token != @token
276+
assert login.sid != @sid
271277
assert login.created_at == @login.created_at
272278
assert login.last_login > @login.last_login
273-
assert conn.cookies[@auth_cookie] == "user.#{login.serial}.#{login.token}"
279+
280+
assert conn.cookies[@auth_cookie] ==
281+
"#{Base.encode64(login.username)}.#{login.serial}.#{login.token}"
274282
end
275283

276284
test "deletes the old session from the store when authenticating from an
@@ -476,7 +484,7 @@ defmodule Expected.PlugsTest do
476484
login", %{conn: conn} do
477485
conn =
478486
conn
479-
|> put_req_cookie(@auth_cookie, "some_user.some_serial.some_token")
487+
|> put_req_cookie(@auth_cookie, @no_login_cookie)
480488
|> fetch_session()
481489
|> authenticate()
482490

@@ -491,7 +499,7 @@ defmodule Expected.PlugsTest do
491499
} do
492500
conn =
493501
conn
494-
|> put_req_cookie(@auth_cookie, "some_user.some_serial.some_token")
502+
|> put_req_cookie(@auth_cookie, @no_login_cookie)
495503
|> fetch_session()
496504
|> authenticate()
497505
|> send_resp(:ok, "")
@@ -503,7 +511,7 @@ defmodule Expected.PlugsTest do
503511
expected one", %{conn: conn} do
504512
conn =
505513
conn
506-
|> put_req_cookie(@auth_cookie, "user.serial.bad_token")
514+
|> put_req_cookie(@auth_cookie, @bad_token_cookie)
507515
|> fetch_session()
508516
|> authenticate()
509517

@@ -517,7 +525,7 @@ defmodule Expected.PlugsTest do
517525
test "deletes the auth_cookie if the token does not match", %{conn: conn} do
518526
conn =
519527
conn
520-
|> put_req_cookie(@auth_cookie, "user.serial.bad_token")
528+
|> put_req_cookie(@auth_cookie, @bad_token_cookie)
521529
|> fetch_session()
522530
|> authenticate()
523531
|> send_resp(:ok, "")
@@ -529,7 +537,7 @@ defmodule Expected.PlugsTest do
529537
conn: conn
530538
} do
531539
conn
532-
|> put_req_cookie(@auth_cookie, "user.serial.bad_token")
540+
|> put_req_cookie(@auth_cookie, @bad_token_cookie)
533541
|> fetch_session()
534542
|> authenticate()
535543

@@ -563,14 +571,14 @@ defmodule Expected.PlugsTest do
563571
end
564572

565573
test "deletes the session if there is valid auth_cookie", %{conn: conn} do
566-
SessionStore.put(nil, "sid", %{"a" => "b"}, @ets_table)
574+
SessionStore.put(nil, @sid, %{"a" => "b"}, @ets_table)
567575

568576
conn
569577
|> put_req_cookie(@auth_cookie, @auth_cookie_content)
570578
|> fetch_session()
571579
|> logout()
572580

573-
assert SessionStore.get(nil, "sid", @ets_table) == {nil, %{}}
581+
assert SessionStore.get(nil, @sid, @ets_table) == {nil, %{}}
574582
end
575583

576584
test "deletes the auth cookie", %{conn: conn} do
@@ -587,7 +595,7 @@ defmodule Expected.PlugsTest do
587595
test "deletes the session cookie", %{conn: conn} do
588596
conn =
589597
conn
590-
|> put_req_cookie(@session_cookie, "sid")
598+
|> put_req_cookie(@session_cookie, @sid)
591599
|> put_req_cookie(@auth_cookie, @auth_cookie_content)
592600
|> fetch_session()
593601
|> logout()
@@ -614,7 +622,7 @@ defmodule Expected.PlugsTest do
614622
} do
615623
conn =
616624
conn
617-
|> put_req_cookie(@auth_cookie, "some_user.some_serial.some_token")
625+
|> put_req_cookie(@auth_cookie, @no_login_cookie)
618626
|> fetch_session()
619627
|> logout()
620628
|> send_resp(:ok, "")

test/expected_test.exs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ defmodule ExpectedTest do
1515
:ok = MemoryStore.put(@other_login, @server)
1616

1717
# Also put a valid session for @login.
18-
SessionStore.put(nil, "sid", %{"a" => "b"}, @ets_table)
18+
SessionStore.put(nil, @sid, %{"a" => "b"}, @ets_table)
1919

2020
:ok
2121
end
@@ -42,20 +42,20 @@ defmodule ExpectedTest do
4242
setup [:with_login]
4343

4444
test "lists logins for the given user" do
45-
assert Expected.list_user_logins("user") == [@login]
45+
assert Expected.list_user_logins(@username) == [@login]
4646
end
4747
end
4848

4949
describe "delete_login/2" do
5050
setup [:with_login]
5151

5252
test "deletes a login if it exists" do
53-
assert :ok = Expected.delete_login("user", "serial")
54-
assert {:error, :no_login} = MemoryStore.get("user", "serial", @server)
53+
assert :ok = Expected.delete_login(@username, @serial)
54+
assert {:error, :no_login} = MemoryStore.get(@username, @serial, @server)
5555
end
5656

5757
test "deletes the session associated with the login if it exists" do
58-
assert :ok = Expected.delete_login("user", "serial")
58+
assert :ok = Expected.delete_login(@username, @serial)
5959
assert SessionStore.get(nil, "sid", @ets_table) == {nil, %{}}
6060
end
6161

@@ -68,12 +68,12 @@ defmodule ExpectedTest do
6868
setup [:with_login]
6969

7070
test "deletes all user logins for the given username" do
71-
assert :ok = Expected.delete_all_user_logins("user")
72-
assert MemoryStore.list_user_logins("user", @server) == []
71+
assert :ok = Expected.delete_all_user_logins(@username)
72+
assert MemoryStore.list_user_logins(@username, @server) == []
7373
end
7474

7575
test "deletes the sessions associated with the logins if they exist" do
76-
assert :ok = Expected.delete_all_user_logins("user")
76+
assert :ok = Expected.delete_all_user_logins(@username)
7777
assert SessionStore.get(nil, "sid", @ets_table) == {nil, %{}}
7878
end
7979

@@ -89,7 +89,7 @@ defmodule ExpectedTest do
8989
:ok = MemoryStore.put(@old_login, @server)
9090

9191
assert :ok = Expected.clean_old_logins(@three_months)
92-
assert MemoryStore.list_user_logins("user", @server) == [@login]
92+
assert MemoryStore.list_user_logins(@username, @server) == [@login]
9393
end
9494

9595
test "cleans the sessions associated with the old logins" do

test/support/expected_case.ex

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,15 @@ defmodule Expected.Case do
2121
@four_months System.convert_time_unit(10_368_000, :seconds, :native)
2222
@four_months_ago @now - @four_months
2323

24+
@username "user"
25+
@serial "serial"
26+
@token "token"
27+
@sid "sid"
2428
@login %Login{
25-
username: "user",
26-
serial: "serial",
27-
token: "token",
28-
sid: "sid",
29+
username: @username,
30+
serial: @serial,
31+
token: @token,
32+
sid: @sid,
2933
created_at: @now,
3034
last_login: @now,
3135
last_ip: {127, 0, 0, 1},

0 commit comments

Comments
 (0)