Permalink
Browse files

cleanups

  • Loading branch information...
1 parent 0cc6aad commit dc3e489dd231c7a4baad24b32c5dda6d1bf62a56 @dvv committed Mar 30, 2013
Showing with 95 additions and 557 deletions.
  1. +56 −22 README.md
  2. +21 −12 src/cowboy_request.erl
  3. +10 −74 src/cowboy_social.erl
  4. +8 −10 src/cowboy_social_profile.erl
  5. +0 −438 src/cowboy_social_provider.erl
  6. +0 −1 src/cowboy_social_vkontakte.erl
View
@@ -18,45 +18,79 @@ Router configuration
--------------
```erlang
-% Authorize via Google
+% Use :action binding
+{"/auth/facebook/:action", cowboy_social, [
+ {client_id, <<"...">>},
+ {client_secret, <<"...">>},
+ {callback_uri, <<"/auth/facebook/callback">>},
+ {scope, <<"email">>},
+ {authorize_uri, <<"https://www.facebook.com/dialog/oauth">>},
+ {token_uri, <<"https://graph.facebook.com/oauth/access_token">>}
+]},
+{"/auth/github/:action", cowboy_social, [
+ {client_id, <<"...">>},
+ {client_secret, <<"...">>},
+ {callback_uri, <<"/auth/github/callback">>},
+ {scope, <<>>},
+ {authorize_uri, <<"https://github.com/login/oauth/authorize">>},
+ {token_uri, <<"https://github.com/login/oauth/access_token">>}
+]},
{"/auth/google/:action", cowboy_social, [
- {provider, cowboy_social_google},
- % At the end of the flow this handler will be called as
- % Mod:Fun({ok, Auth, Profile}, Req, State) or Mod:Fun({error, Reason}, Req, State)
- {handler, {Mod, Fun}},
{client_id, <<"...">>},
{client_secret, <<"...">>},
- {scope, <<>>}, % additional permissions
- {callback_uri, <<"/auth/google/callback">>}
-]}.
-
-% In case of compliant provider we can just tune provider
-{"/auth/good-provider/:action", cowboy_social, [
- {provider, cowboy_social_generic},
- {handler, {Mod, Fun}},
+ {callback_uri, <<"/auth/google/callback">>},
+ {scope, << "https://www.googleapis.com/auth/userinfo.email ",
+ "https://www.googleapis.com/auth/userinfo.profile" >>},
+ {authorize_uri, <<"https://accounts.google.com/o/oauth2/auth">>},
+ {token_uri, <<"https://accounts.google.com/o/oauth2/token">>}
+]},
+{"/auth/mailru/:action", cowboy_social, [
{client_id, <<"...">>},
{client_secret, <<"...">>},
- {scope, <<>>}, % additional permissions
- {callback_uri, <<"/auth/good-provider/callback">>},
- % tune generic provider
- {provider_name, <<"good-provider">>},
- {authorize_url, <<"https://good.provider.org/oauth2/authorize">>},
- {access_token_url, <<"https://good.provider.org/oauth2/access_token">>},
- {profile_url, <<"https://good.provider.org/profile">>}
+ {secret_key, <<"f431aea09762dbad13c2440955e12aee">>},
+ {callback_uri, <<"/auth/mailru/callback">>},
+ {scope, <<>>},
+ {authorize_uri, <<"https://connect.mail.ru/oauth/authorize">>},
+ {token_uri, <<"https://connect.mail.ru/oauth/token">>}
+]},
+{"/auth/paypal/:action", cowboy_social, [
+ {client_id, <<"...">>},
+ {client_secret, <<"...">>},
+ {callback_uri, <<"/auth/paypal/callback">>},
+ {scope, <<"https://identity.x.com/xidentity/resources/profile/me">>},
+ {authorize_uri, <<"https://identity.x.com/xidentity/resources/authorize">>},
+ {token_uri, <<"https://identity.x.com/xidentity/oauthtokenservice">>}
+]},
+{"/auth/vkontakte/:action", cowboy_social, [
+ {client_id, <<"...">>},
+ {client_secret, <<"...">>},
+ {callback_uri, <<"/auth/vkontakte/callback">>},
+ {scope, <<"uid,first_name,last_name,sex,photo">>},
+ {authorize_uri, <<"https://oauth.vk.com/authorize">>},
+ {token_uri, <<"https://oauth.vk.com/access_token">>}
+]},
+{"/auth/yandex/:action", cowboy_social, [
+ {client_id, <<"...">>},
+ {client_secret, <<"...">>},
+ {callback_uri, <<"/auth/yandex/callback">>},
+ {scope, <<>>},
+ {authorize_uri, <<"https://oauth.yandex.ru/authorize">>},
+ {token_uri, <<"https://oauth.yandex.ru/token">>}
]}.
```
Supported providers
--------------
- Facebook
-- Generic one (no separate module required, just some parameters for the handler)
- Github
- Google
- Mail.ru
- PayPal
- Vkontakte
- Yandex
-- add more, this is very simple
+- Add more yourself -- this is very simple -- tune `scope`, `authorize_uri` and `token_uri` options.
+
+Please, consider to feedback here successful options you found for another providers.
License (MIT)
-------
View
@@ -33,23 +33,27 @@ request(Method, URL, Headers, Body) ->
{ok, Client2} = cowboy_client:request(Method, URL, [
{<<"connection">>, <<"close">>},
{<<"accept-encoding">>, <<"identity">>},
+ % {<<"accept">>, <<"application/json, text/html">>},
{<<"accept">>, <<"application/json">>},
+ {<<"content-type">>, <<"application/x-www-form-urlencoded">>},
{<<"pragma">>, <<"no-cache">>},
{<<"cache-control">>,
<<"private, max-age: 0, no-cache, must-revalidate">>}
| Headers
], Body, Client),
Result = case cowboy_client:response(Client2) of
- {ok, _Status, _ResHeaders, Client3} ->
+ {ok, Status, _ResHeaders, Client3} ->
case Client3#client.state of
% @fixme dirty hack, reports only first read chunk
request ->
- {ok, Client3#client.buffer};
+% pecypc_log:info({buffer, _Status, Client3}),
+ {ok, Status, Client3#client.buffer};
response_body ->
case cowboy_client:response_body(Client3) of
{ok, ResBody, _} ->
+% pecypc_log:info({body, _Status, ResBody}),
% @todo analyze Status
- {ok, ResBody};
+ {ok, Status, ResBody};
Else ->
Else
end
@@ -84,7 +88,7 @@ binary_join([H], _Sep) ->
binary_join([H | T], Sep) ->
<< H/binary, Sep/binary, (binary_join(T, Sep))/binary >>.
-parse({ok, JSON}) ->
+parse(JSON) ->
case jsx:decode(JSON, [{error_handler, fun(_, _, _) -> {error, badarg} end}])
of
{error, _} ->
@@ -93,16 +97,21 @@ parse({ok, JSON}) ->
{ok, []};
Hash ->
{ok, Hash}
- end;
-parse(_) ->
- {error, badarg}.
+ end.
get_json(URL, Data) ->
- parse(request(<<"GET">>,
- << URL/binary, $?,
- (urlencode(Data))/binary >>, [], <<>>)).
+ case request(<<"GET">>, <<
+ URL/binary, $?, (urlencode(Data))/binary >>, [], <<>>)
+ of
+ {ok, 200, JSON} -> parse(JSON);
+ _ -> {error, badarg}
+ end.
post_for_json(URL, Data) ->
- parse(request(<<"POST">>, URL, [
+ case request(<<"POST">>, URL, [
{<<"content-type">>, <<"application/x-www-form-urlencoded">>}
- ], urlencode(Data))).
+ ], urlencode(Data))
+ of
+ {ok, 200, JSON} -> parse(JSON);
+ _ -> {error, badarg}
+ end.
View
@@ -20,26 +20,16 @@
]).
-record(state, {
- provider,
action,
options
}).
init(_Transport, Req, Opts) ->
- {Provider, Req2} = cowboy_req:binding(provider, Req),
- {Action, Req3} = cowboy_req:binding(action, Req2, <<"login">>),
- % @todo unknown provider
- case lists:keyfind(Provider, 1, Opts) of
- {_, ProviderOpts} ->
- {upgrade, protocol, cowboy_rest, Req3, #state{
- provider = Provider,
- action = Action,
- options = ProviderOpts
- }};
- false ->
- {ok, Req4} = cowboy_req:reply(404, [], <<>>, Req3),
- {shutdown, Req4, undefined}
- end.
+ {Action, Req2} = cowboy_req:binding(action, Req, <<"login">>),
+ {upgrade, protocol, cowboy_rest, Req2, #state{
+ action = Action,
+ options = Opts
+ }}.
terminate(_Reason, _Req, _State) ->
ok.
@@ -106,7 +96,7 @@ get_json(Req, State) ->
%%
%% User agent initiates the flow.
%%
-action(Req, #state{action = <<"login">>, provider = P, options = O}) ->
+action(Req, #state{action = <<"login">>, options = O}) ->
{Type, Req2} = cowboy_req:qs_val(<<"response_type">>, Req, <<"code">>),
{Opaque, Req3} = cowboy_req:qs_val(<<"state">>, Req2, <<>>),
% redirect to provider authorization page
@@ -115,12 +105,11 @@ action(Req, #state{action = <<"login">>, provider = P, options = O}) ->
% {<<"location">>, Mod:authorize(Opts)}
% ], <<>>, Req3),
% {halt, Req4, State};
- redirect(key(authorize_url, O, authorize_url(P)), [
+ redirect(key(authorize_uri, O), [
{client_id, key(client_id, O)},
{redirect_uri, key(callback_uri, O)},
{response_type, Type},
- {scope, << (default_scope(P))/binary,
- (key(scope, O, <<>>))/binary >>},
+ {scope, key(scope, O)},
{state, Opaque}
], Req3);
@@ -136,14 +125,14 @@ action(Req, State = #state{action = <<"callback">>}) ->
{error, Error, Req2}
end.
-check_code(Req, State = #state{provider = P, options = O}) ->
+check_code(Req, State = #state{options = O}) ->
case cowboy_req:qs_val(<<"code">>, Req) of
{undefined, Req2} ->
check_token(Req2, State);
{Code, Req2} ->
%% Provider redirected back to the client with authorization code.
%% Exchange authorization code for access token.
- post(key(token_url, O, token_url(P)), [
+ post(key(token_uri, O), [
{code, Code},
{client_id, key(client_id, O)},
{client_secret, key(client_secret, O)},
@@ -194,7 +183,6 @@ redirect(Uri, Params, Req) ->
post(Url, Params, Req) ->
try cowboy_request:post_for_json(Url, Params) of
{ok, Auth} ->
-% pecypc_log:info({auth, Auth}),
case lists:keyfind(<<"error">>, 1, Auth) of
false ->
{ok, [
@@ -222,55 +210,3 @@ key(Key, List, Def) ->
keyreplace(Key, List, Value) ->
lists:keyreplace(Key, 1, List, {Key, Value}).
-
-%%
-%%------------------------------------------------------------------------------
-%% Providers
-%%------------------------------------------------------------------------------
-%%
-
-authorize_url(<<"facebook">>) ->
- <<"https://www.facebook.com/dialog/oauth">>;
-authorize_url(<<"github">>) ->
- <<"https://github.com/login/oauth/authorize">>;
-authorize_url(<<"google">>) ->
- <<"https://accounts.google.com/o/oauth2/auth">>;
-authorize_url(<<"mailru">>) ->
- <<"https://connect.mail.ru/oauth/authorize">>;
-authorize_url(<<"paypal">>) ->
- <<"https://identity.x.com/xidentity/resources/authorize">>;
-authorize_url(<<"vkontakte">>) ->
- <<"https://oauth.vk.com/authorize">>;
-authorize_url(<<"yandex">>) ->
- <<"https://oauth.yandex.ru/authorize">>;
-authorize_url(_) ->
- undefined.
-
-token_url(<<"facebook">>) ->
- <<"https://graph.facebook.com/oauth/access_token">>;
-token_url(<<"github">>) ->
- <<"https://github.com/login/oauth/access_token">>;
-token_url(<<"google">>) ->
- <<"https://accounts.google.com/o/oauth2/token">>;
-token_url(<<"mailru">>) ->
- <<"https://connect.mail.ru/oauth/token">>;
-token_url(<<"paypal">>) ->
- <<"https://identity.x.com/xidentity/oauthtokenservice">>;
-token_url(<<"vkontakte">>) ->
- <<"https://oauth.vk.com/access_token">>;
-token_url(<<"yandex">>) ->
- <<"https://oauth.yandex.ru/token">>;
-token_url(_) ->
- undefined.
-
-default_scope(<<"facebook">>) ->
- <<"email">>;
-default_scope(<<"google">>) ->
- << "https://www.googleapis.com/auth/userinfo.email ",
- "https://www.googleapis.com/auth/userinfo.profile" >>;
-default_scope(<<"paypal">>) ->
- <<"https://identity.x.com/xidentity/resources/profile/me">>;
-default_scope(<<"vkontakte">>) ->
- <<"uid,first_name,last_name,sex,photo">>;
-default_scope(_) ->
- <<>>.
@@ -19,20 +19,16 @@
]).
-record(state, {
- provider,
action,
options,
token
}).
init(_Transport, Req, Opts) ->
- {Provider, Req2} = cowboy_req:binding(provider, Req),
- {Action, Req3} = cowboy_req:binding(action, Req2),
- {_, ProviderOpts} = lists:keyfind(Provider, 1, Opts),
- {upgrade, protocol, cowboy_rest, Req3, #state{
- provider = Provider,
+ {Action, Req2} = cowboy_req:binding(action, Req, <<"login">>),
+ {upgrade, protocol, cowboy_rest, Req2, #state{
action = Action,
- options = ProviderOpts
+ options = Opts
}}.
terminate(_Reason, _Req, _State) ->
@@ -64,10 +60,12 @@ content_types_provided(Req, State) ->
{{<<"application">>, <<"json">>, []}, get_json}
], Req, State}.
-get_json(Req, State = #state{
- provider = Provider, action = Action, options = Opts, token = Token}) ->
+get_json(Req, State = #state{action = Action, options = Opts, token = Token}) ->
% @fixme atoms are not purged!
- Mod = binary_to_atom(<< "cowboy_social_", Provider/binary >>, latin1),
+ {_, Provider} = lists:keyfind(provider, 1, Opts),
+ Mod = binary_to_atom(<<
+ "cowboy_social_", (atom_to_binary(Provider, latin1))/binary
+ >>, latin1),
Fun = binary_to_atom(Action, latin1),
case Mod:Fun(Token, Opts) of
{ok, Result} ->
Oops, something went wrong.

0 comments on commit dc3e489

Please sign in to comment.