diff --git a/Gruntfile.js b/Gruntfile.js
deleted file mode 100644
index d856080..0000000
--- a/Gruntfile.js
+++ /dev/null
@@ -1,413 +0,0 @@
-// Generated on 2014-03-14 using generator-angular 0.7.1
-'use strict';
-
-// # Globbing
-// for performance reasons we're only matching one level down:
-// 'test/spec/{,*/}*.js'
-// use this if you want to recursively match all subfolders:
-// 'test/spec/**/*.js'
-
-module.exports = function (grunt) {
-
- // Load grunt tasks automatically
- require('load-grunt-tasks')(grunt);
-
- // Time how long tasks take. Can help when optimizing build times
- require('time-grunt')(grunt);
-
- // configurable paths
- var yeomanConfig = {
- app: 'app',
- dist: 'dist',
- test: 'test'
- };
-
- try {
- var component = require('./bower.json')
- yeomanConfig.name = component.name || 'no-name';
- yeomanConfig.version = component.version || '0.0.0.undefined';
- } catch (e) {}
-
-
- // Define the configuration for all the tasks
- grunt.initConfig({
-
- // Project settings
- yeoman: yeomanConfig,
-
- // Watches files for changes and runs tasks based on the changed files
- watch: {
- js: {
- files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
- tasks: [],
- options: {
- livereload: true
- }
- },
- jsTest: {
- files: ['test/spec/{,*/}*.js'],
- tasks: ['newer:jshint:test', 'karma']
- },
- styles: {
- files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
- tasks: ['newer:copy:styles', 'autoprefixer']
- },
- gruntfile: {
- files: ['Gruntfile.js']
- },
- livereload: {
- options: {
- livereload: '<%= connect.options.livereload %>'
- },
- files: [
- '<%= yeoman.app %>/{,*/}*.html',
- '.tmp/styles/{,*/}*.css',
- '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
- ]
- }
- },
-
- // The actual grunt server settings
- connect: {
- options: {
- port: 9000,
- // Change this to '0.0.0.0' to access the server from outside.
- hostname: 'localhost',
- livereload: 35729
- },
- livereload: {
- options: {
- open: true,
- base: [
- '.tmp',
- 'test',
- '<%= yeoman.app %>'
- ]
- }
- },
- test: {
- options: {
- port: 9001,
- base: [
- '.tmp',
- 'test',
- '<%= yeoman.app %>'
- ]
- }
- },
- dist: {
- options: {
- base: '<%= yeoman.dist %>'
- }
- }
- },
-
- // Make sure code styles are up to par and there are no obvious mistakes
- jshint: {
- options: {
- jshintrc: '.jshintrc',
- reporter: require('jshint-stylish')
- },
- all: [
- 'Gruntfile.js',
- '<%= yeoman.app %>/scripts/{,*/}*.js'
- ],
- test: {
- options: {
- jshintrc: 'test/.jshintrc'
- },
- src: ['test/spec/{,*/}*.js']
- }
- },
-
- // Empties folders to start fresh
- clean: {
- dist: {
- files: [{
- dot: true,
- src: [
- '.tmp',
- '<%= yeoman.dist %>/*',
- '!<%= yeoman.dist %>/.git*'
- ]
- }]
- },
- server: '.tmp'
- },
-
- // Add vendor prefixed styles
- autoprefixer: {
- options: {
- browsers: ['last 1 version']
- },
- dist: {
- files: [{
- expand: true,
- cwd: '.tmp/styles/',
- src: '{,*/}*.css',
- dest: '.tmp/styles/'
- }]
- }
- },
-
- // Automatically inject Bower components into the app
- 'bower-install': {
- app: {
- html: '<%= yeoman.app %>/index.html',
- ignorePath: '<%= yeoman.app %>/'
- }
- },
-
- // Renames files for browser caching purposes
- rev: {
- dist: {
- files: {
- src: [
- '<%= yeoman.dist %>/scripts/{,*/}*.js',
- '<%= yeoman.dist %>/styles/{,*/}*.css',
- '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
- '<%= yeoman.dist %>/styles/fonts/*'
- ]
- }
- }
- },
-
- // Reads HTML for usemin blocks to enable smart builds that automatically
- // concat, minify and revision files. Creates configurations in memory so
- // additional tasks can operate on them
- useminPrepare: {
- html: '<%= yeoman.app %>/index.html',
- options: {
- dest: '<%= yeoman.dist %>'
- }
- },
-
- // Performs rewrites based on rev and the useminPrepare configuration
- usemin: {
- html: ['<%= yeoman.dist %>/{,*/}*.html'],
- css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
- options: {
- assetsDirs: ['<%= yeoman.dist %>']
- }
- },
-
- // The following *-min tasks produce minified files in the dist folder
- imagemin: {
- dist: {
- files: [{
- //expand: true,
- //cwd: '<%= yeoman.app %>/images',
- //src: '{,*/}*.{png,jpg,jpeg,gif}',
- //dest: '<%= yeoman.dist %>/images'
- }]
- }
- },
- svgmin: {
- dist: {
- files: [{
- expand: true,
- cwd: '<%= yeoman.app %>/images',
- src: '{,*/}*.svg',
- dest: '<%= yeoman.dist %>/images'
- }]
- }
- },
- htmlmin: {
- dist: {
- options: {
- collapseWhitespace: true,
- collapseBooleanAttributes: true,
- removeCommentsFromCDATA: true,
- removeOptionalTags: true
- },
- files: [{
- expand: true,
- cwd: '<%= yeoman.dist %>',
- src: ['*.html', 'views/{,*/}*.html'],
- dest: '<%= yeoman.dist %>'
- }]
- }
- },
-
- // Allow the use of non-minsafe AngularJS files. Automatically makes it
- // minsafe compatible so Uglify does not destroy the ng references
- ngmin: {
- dist: {
- files: [{
- expand: true,
- cwd: '.tmp/concat/scripts',
- src: '*.js',
- dest: '.tmp/concat/scripts'
- }]
- }
- },
-
- // Replace Google CDN references
- cdnify: {
- dist: {
- html: ['<%= yeoman.dist %>/*.html']
- }
- },
-
- // Copies remaining files to places other tasks can use
- copy: {
- dist: {
- files: [{
- expand: true,
- dot: true,
- cwd: '<%= yeoman.app %>',
- dest: '<%= yeoman.dist %>',
- src: [
- //'*.{ico,png,txt}',
- //'.htaccess',
- //'*.html',
- 'views/{,*/}*.html',
- //'bower_components/**/*',
- //'images/{,*/}*.{webp}',
- //'fonts/*'
- ]
- }, {
- //expand: true,
- //cwd: '.tmp/images',
- //dest: '<%= yeoman.dist %>/images',
- //src: ['generated/*']
- }]
- },
- styles: {
- //expand: true,
- //cwd: '<%= yeoman.app %>/styles',
- //dest: '.tmp/styles/',
- //src: '{,*/}*.css'
- }
- },
-
- // Run some tasks in parallel to speed up the build process
- concurrent: {
- server: [
- 'copy:styles'
- ],
- test: [
- 'copy:styles'
- ],
- dist: [
- 'copy:styles',
- 'imagemin',
- 'svgmin'
- ]
- },
-
- // By default, your `index.html`'s will take care of
- // minification. These next options are pre-configured if you do not wish
- // to use the Usemin blocks.
- // cssmin: {
- // dist: {
- // files: {
- // '<%= yeoman.dist %>/styles/main.css': [
- // '.tmp/styles/{,*/}*.css',
- // '<%= yeoman.app %>/styles/{,*/}*.css'
- // ]
- // }
- // }
- // },
-
- //uglify: {
- //options: {
- //banner: '/* <%= yeoman.name %> - v<%= yeoman.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %> */\n\n'
- //}
- //},
-
- uglify: {
- options: {
- banner: '/* <%= yeoman.name %> - v<%= yeoman.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %> */\n'
- },
- dist: {
- files: {
- '<%= yeoman.dist %>/<%= yeoman.name %>.min.js': [
- '<%= yeoman.dist %>/<%= yeoman.name %>.js'
- ]
- }
- }
- },
- concat: {
- options: {
- banner: '/* <%= yeoman.name %> - v<%= yeoman.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %> */\n\n'
- },
- dist: {
- files: {
- '<%= yeoman.dist %>/<%= yeoman.name %>.js': [
- '.tmp/scripts/{,*/}*.js',
- '<%= yeoman.app %>/scripts/{,*/}*.js'
- ]
- }
- }
- },
-
- // Test settings
- karma: {
- unit: {
- configFile: 'karma.conf.js',
- singleRun: false
- }
- },
- 'string-replace': {
- dist: {
- files: {
- './': 'dist/**/*.*'
- },
- options: {
- replacements: [{
- pattern: /views\/templates\/default\.html/g,
- replacement: 'bower_components/oauth-ng/dist/views/templates/default.html'
- }]
- }
- }
- }
-
- });
-
-
- grunt.registerTask('serve', function (target) {
- if (target === 'dist') {
- return grunt.task.run(['build', 'connect:dist:keepalive']);
- }
-
- grunt.task.run([
- 'clean:server',
- 'bower-install',
- 'concurrent:server',
- 'autoprefixer',
- 'connect:livereload',
- 'watch'
- ]);
- });
-
- grunt.registerTask('server', function () {
- grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
- grunt.task.run(['serve']);
- });
-
- grunt.registerTask('test', [
- 'clean:server',
- 'concurrent:test',
- 'autoprefixer',
- 'connect:test',
- 'karma'
- ]);
-
- grunt.registerTask('build', [
- 'clean:dist',
- 'copy',
- 'useminPrepare',
- 'concat',
- 'ngmin',
- 'uglify',
- 'concat',
- 'string-replace',
- ]);
-
- grunt.registerTask('default', [
- 'newer:jshint',
- 'test',
- 'build'
- ]);
-};
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index e893381..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2013 Andrea Reginato
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index a6a6813..f52905d 100644
--- a/README.md
+++ b/README.md
@@ -1,48 +1,25 @@
-# Angular OAuth 2.0 Directive
+# AngularJS directive for OAuth 2.0
-AngularJS directive for [OAuth 2.0 Implicit Flow](http://tools.ietf.org/html/rfc6749#section-1.3.2).
-
-
-## Documentation
+Source code for the AngularJS directive for OAuth 2.0 [website](http://andreareginato.github.com/oauth-ng).
+[](https://andreareginato.github.com/oauth-ng)
## Contributing
Fork the repo on github and send a pull requests with topic branches.
-Do not forget to provide specs to your contribution.
-
-### Setup
-
-* Fork and clone the repository
-* Run `npm install`
-
-### Unit tests (karma)
-
-* `grunt karma:unit`
-
-### Creating your own distribution
-* Fork and clone the repository
-* Run `npm install`
-* Run `grunt build`
-
-The new distribution files will be created in the `dist/` folder.
-
-### Coding guidelines
-
-Follow [github](https://github.com/styleguide/) guidelines.
### Feedback
Use the [issue tracker](http://github.com/andreareginato/oauth-ng/issues) for bugs.
-[Mail](mailto:touch@lelylan.com) or [Tweet](http://twitter.com/lelylan) us for any idea
-that can improve the project.
+[Mail](mailto:andreareginato@gmail.com) or [Tweet](http://twitter.com/andreareginato)
+us for any idea that can improve the project.
-### Links
+## Links
* [GIT Repository](http://github.com/andreareginato/oauth-ng)
-* [Lelylan Dev Center](http://dev.lelylan.com)
-
+* [The OAuth Bible](http://oauthbible.com/)
+* [Lelylan](http://lelylan.com)
## Authors
@@ -50,14 +27,9 @@ that can improve the project.
## Contributors
-Special thanks to all [contributors](https://github.com/andreareginato/oauth-ng/contributors)
+Special thanks to all [contributors](https://github.com/lelylan/lelylan-ng/contributors)
for submitting patches.
-## Changelog
-
-See [CHANGELOG](https://github.com/andreareginato/oauth-ng/blob/master/CHANGELOG.md)
-
-## Copyright
+## License
-Copyright (c) 2014 [Lelylan](http://lelylan.com).
-See [LICENSE](https://github.com/andreareginato/oauth-ng/blob/master/LICENSE.md) for details.
+See [license](https://github.com/lelylan/lelylan-ng/blob/master/LICENSE.md).
diff --git a/app/.buildignore b/app/.buildignore
deleted file mode 100644
index fc98b8e..0000000
--- a/app/.buildignore
+++ /dev/null
@@ -1 +0,0 @@
-*.coffee
\ No newline at end of file
diff --git a/app/.htaccess b/app/.htaccess
deleted file mode 100644
index cb84cb9..0000000
--- a/app/.htaccess
+++ /dev/null
@@ -1,543 +0,0 @@
-# Apache Configuration File
-
-# (!) Using `.htaccess` files slows down Apache, therefore, if you have access
-# to the main server config file (usually called `httpd.conf`), you should add
-# this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html.
-
-# ##############################################################################
-# # CROSS-ORIGIN RESOURCE SHARING (CORS) #
-# ##############################################################################
-
-# ------------------------------------------------------------------------------
-# | Cross-domain AJAX requests |
-# ------------------------------------------------------------------------------
-
-# Enable cross-origin AJAX requests.
-# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
-# http://enable-cors.org/
-
-#
-# Header set Access-Control-Allow-Origin "*"
-#
-
-# ------------------------------------------------------------------------------
-# | CORS-enabled images |
-# ------------------------------------------------------------------------------
-
-# Send the CORS header for images when browsers request it.
-# https://developer.mozilla.org/en/CORS_Enabled_Image
-# http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html
-# http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/
-
-
-
-
- SetEnvIf Origin ":" IS_CORS
- Header set Access-Control-Allow-Origin "*" env=IS_CORS
-
-
-
-
-# ------------------------------------------------------------------------------
-# | Web fonts access |
-# ------------------------------------------------------------------------------
-
-# Allow access from all domains for web fonts
-
-
-
- Header set Access-Control-Allow-Origin "*"
-
-
-
-
-# ##############################################################################
-# # ERRORS #
-# ##############################################################################
-
-# ------------------------------------------------------------------------------
-# | 404 error prevention for non-existing redirected folders |
-# ------------------------------------------------------------------------------
-
-# Prevent Apache from returning a 404 error for a rewrite if a directory
-# with the same name does not exist.
-# http://httpd.apache.org/docs/current/content-negotiation.html#multiviews
-# http://www.webmasterworld.com/apache/3808792.htm
-
-Options -MultiViews
-
-# ------------------------------------------------------------------------------
-# | Custom error messages / pages |
-# ------------------------------------------------------------------------------
-
-# You can customize what Apache returns to the client in case of an error (see
-# http://httpd.apache.org/docs/current/mod/core.html#errordocument), e.g.:
-
-ErrorDocument 404 /404.html
-
-
-# ##############################################################################
-# # INTERNET EXPLORER #
-# ##############################################################################
-
-# ------------------------------------------------------------------------------
-# | Better website experience |
-# ------------------------------------------------------------------------------
-
-# Force IE to render pages in the highest available mode in the various
-# cases when it may not: http://hsivonen.iki.fi/doctype/ie-mode.pdf.
-
-
- Header set X-UA-Compatible "IE=edge"
- # `mod_headers` can't match based on the content-type, however, we only
- # want to send this header for HTML pages and not for the other resources
-
- Header unset X-UA-Compatible
-
-
-
-# ------------------------------------------------------------------------------
-# | Cookie setting from iframes |
-# ------------------------------------------------------------------------------
-
-# Allow cookies to be set from iframes in IE.
-
-#
-# Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\""
-#
-
-# ------------------------------------------------------------------------------
-# | Screen flicker |
-# ------------------------------------------------------------------------------
-
-# Stop screen flicker in IE on CSS rollovers (this only works in
-# combination with the `ExpiresByType` directives for images from below).
-
-# BrowserMatch "MSIE" brokenvary=1
-# BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1
-# BrowserMatch "Opera" !brokenvary
-# SetEnvIf brokenvary 1 force-no-vary
-
-
-# ##############################################################################
-# # MIME TYPES AND ENCODING #
-# ##############################################################################
-
-# ------------------------------------------------------------------------------
-# | Proper MIME types for all files |
-# ------------------------------------------------------------------------------
-
-
-
- # Audio
- AddType audio/mp4 m4a f4a f4b
- AddType audio/ogg oga ogg
-
- # JavaScript
- # Normalize to standard type (it's sniffed in IE anyways):
- # http://tools.ietf.org/html/rfc4329#section-7.2
- AddType application/javascript js jsonp
- AddType application/json json
-
- # Video
- AddType video/mp4 mp4 m4v f4v f4p
- AddType video/ogg ogv
- AddType video/webm webm
- AddType video/x-flv flv
-
- # Web fonts
- AddType application/font-woff woff
- AddType application/vnd.ms-fontobject eot
-
- # Browsers usually ignore the font MIME types and sniff the content,
- # however, Chrome shows a warning if other MIME types are used for the
- # following fonts.
- AddType application/x-font-ttf ttc ttf
- AddType font/opentype otf
-
- # Make SVGZ fonts work on iPad:
- # https://twitter.com/FontSquirrel/status/14855840545
- AddType image/svg+xml svg svgz
- AddEncoding gzip svgz
-
- # Other
- AddType application/octet-stream safariextz
- AddType application/x-chrome-extension crx
- AddType application/x-opera-extension oex
- AddType application/x-shockwave-flash swf
- AddType application/x-web-app-manifest+json webapp
- AddType application/x-xpinstall xpi
- AddType application/xml atom rdf rss xml
- AddType image/webp webp
- AddType image/x-icon ico
- AddType text/cache-manifest appcache manifest
- AddType text/vtt vtt
- AddType text/x-component htc
- AddType text/x-vcard vcf
-
-
-
-# ------------------------------------------------------------------------------
-# | UTF-8 encoding |
-# ------------------------------------------------------------------------------
-
-# Use UTF-8 encoding for anything served as `text/html` or `text/plain`.
-AddDefaultCharset utf-8
-
-# Force UTF-8 for certain file formats.
-
- AddCharset utf-8 .atom .css .js .json .rss .vtt .webapp .xml
-
-
-
-# ##############################################################################
-# # URL REWRITES #
-# ##############################################################################
-
-# ------------------------------------------------------------------------------
-# | Rewrite engine |
-# ------------------------------------------------------------------------------
-
-# Turning on the rewrite engine and enabling the `FollowSymLinks` option is
-# necessary for the following directives to work.
-
-# If your web host doesn't allow the `FollowSymlinks` option, you may need to
-# comment it out and use `Options +SymLinksIfOwnerMatch` but, be aware of the
-# performance impact: http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks
-
-# Also, some cloud hosting services require `RewriteBase` to be set:
-# http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site
-
-
- Options +FollowSymlinks
- # Options +SymLinksIfOwnerMatch
- RewriteEngine On
- # RewriteBase /
-
-
-# ------------------------------------------------------------------------------
-# | Suppressing / Forcing the "www." at the beginning of URLs |
-# ------------------------------------------------------------------------------
-
-# The same content should never be available under two different URLs especially
-# not with and without "www." at the beginning. This can cause SEO problems
-# (duplicate content), therefore, you should choose one of the alternatives and
-# redirect the other one.
-
-# By default option 1 (no "www.") is activated:
-# http://no-www.org/faq.php?q=class_b
-
-# If you'd prefer to use option 2, just comment out all the lines from option 1
-# and uncomment the ones from option 2.
-
-# IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME!
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-# Option 1: rewrite www.example.com → example.com
-
-
- RewriteCond %{HTTPS} !=on
- RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
- RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
-
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-# Option 2: rewrite example.com → www.example.com
-
-# Be aware that the following might not be a good idea if you use "real"
-# subdomains for certain parts of your website.
-
-#
-# RewriteCond %{HTTPS} !=on
-# RewriteCond %{HTTP_HOST} !^www\..+$ [NC]
-# RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
-#
-
-
-# ##############################################################################
-# # SECURITY #
-# ##############################################################################
-
-# ------------------------------------------------------------------------------
-# | Content Security Policy (CSP) |
-# ------------------------------------------------------------------------------
-
-# You can mitigate the risk of cross-site scripting and other content-injection
-# attacks by setting a Content Security Policy which whitelists trusted sources
-# of content for your site.
-
-# The example header below allows ONLY scripts that are loaded from the current
-# site's origin (no inline scripts, no CDN, etc). This almost certainly won't
-# work as-is for your site!
-
-# To get all the details you'll need to craft a reasonable policy for your site,
-# read: http://html5rocks.com/en/tutorials/security/content-security-policy (or
-# see the specification: http://w3.org/TR/CSP).
-
-#
-# Header set Content-Security-Policy "script-src 'self'; object-src 'self'"
-#
-# Header unset Content-Security-Policy
-#
-#
-
-# ------------------------------------------------------------------------------
-# | File access |
-# ------------------------------------------------------------------------------
-
-# Block access to directories without a default document.
-# Usually you should leave this uncommented because you shouldn't allow anyone
-# to surf through every directory on your server (which may includes rather
-# private places like the CMS's directories).
-
-
- Options -Indexes
-
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-# Block access to hidden files and directories.
-# This includes directories used by version control systems such as Git and SVN.
-
-
- RewriteCond %{SCRIPT_FILENAME} -d [OR]
- RewriteCond %{SCRIPT_FILENAME} -f
- RewriteRule "(^|/)\." - [F]
-
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-# Block access to backup and source files.
-# These files may be left by some text editors and can pose a great security
-# danger when anyone has access to them.
-
-
- Order allow,deny
- Deny from all
- Satisfy All
-
-
-# ------------------------------------------------------------------------------
-# | Secure Sockets Layer (SSL) |
-# ------------------------------------------------------------------------------
-
-# Rewrite secure requests properly to prevent SSL certificate warnings, e.g.:
-# prevent `https://www.example.com` when your certificate only allows
-# `https://secure.example.com`.
-
-#
-# RewriteCond %{SERVER_PORT} !^443
-# RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L]
-#
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-# Force client-side SSL redirection.
-
-# If a user types "example.com" in his browser, the above rule will redirect him
-# to the secure version of the site. That still leaves a window of opportunity
-# (the initial HTTP connection) for an attacker to downgrade or redirect the
-# request. The following header ensures that browser will ONLY connect to your
-# server via HTTPS, regardless of what the users type in the address bar.
-# http://www.html5rocks.com/en/tutorials/security/transport-layer-security/
-
-#
-# Header set Strict-Transport-Security max-age=16070400;
-#
-
-# ------------------------------------------------------------------------------
-# | Server software information |
-# ------------------------------------------------------------------------------
-
-# Avoid displaying the exact Apache version number, the description of the
-# generic OS-type and the information about Apache's compiled-in modules.
-
-# ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`!
-
-# ServerTokens Prod
-
-
-# ##############################################################################
-# # WEB PERFORMANCE #
-# ##############################################################################
-
-# ------------------------------------------------------------------------------
-# | Compression |
-# ------------------------------------------------------------------------------
-
-
-
- # Force compression for mangled headers.
- # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping
-
-
- SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
- RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
-
-
-
- # Compress all output labeled with one of the following MIME-types
- # (for Apache versions below 2.3.7, you don't need to enable `mod_filter`
- # and can remove the `` and ` ` lines
- # as `AddOutputFilterByType` is still in the core directives).
-
- AddOutputFilterByType DEFLATE application/atom+xml \
- application/javascript \
- application/json \
- application/rss+xml \
- application/vnd.ms-fontobject \
- application/x-font-ttf \
- application/x-web-app-manifest+json \
- application/xhtml+xml \
- application/xml \
- font/opentype \
- image/svg+xml \
- image/x-icon \
- text/css \
- text/html \
- text/plain \
- text/x-component \
- text/xml
-
-
-
-
-# ------------------------------------------------------------------------------
-# | Content transformations |
-# ------------------------------------------------------------------------------
-
-# Prevent some of the mobile network providers from modifying the content of
-# your site: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5.
-
-#
-# Header set Cache-Control "no-transform"
-#
-
-# ------------------------------------------------------------------------------
-# | ETag removal |
-# ------------------------------------------------------------------------------
-
-# Since we're sending far-future expires headers (see below), ETags can
-# be removed: http://developer.yahoo.com/performance/rules.html#etags.
-
-# `FileETag None` is not enough for every server.
-
- Header unset ETag
-
-
-FileETag None
-
-# ------------------------------------------------------------------------------
-# | Expires headers (for better cache control) |
-# ------------------------------------------------------------------------------
-
-# The following expires headers are set pretty far in the future. If you don't
-# control versioning with filename-based cache busting, consider lowering the
-# cache time for resources like CSS and JS to something like 1 week.
-
-
-
- ExpiresActive on
- ExpiresDefault "access plus 1 month"
-
- # CSS
- ExpiresByType text/css "access plus 1 year"
-
- # Data interchange
- ExpiresByType application/json "access plus 0 seconds"
- ExpiresByType application/xml "access plus 0 seconds"
- ExpiresByType text/xml "access plus 0 seconds"
-
- # Favicon (cannot be renamed!)
- ExpiresByType image/x-icon "access plus 1 week"
-
- # HTML components (HTCs)
- ExpiresByType text/x-component "access plus 1 month"
-
- # HTML
- ExpiresByType text/html "access plus 0 seconds"
-
- # JavaScript
- ExpiresByType application/javascript "access plus 1 year"
-
- # Manifest files
- ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds"
- ExpiresByType text/cache-manifest "access plus 0 seconds"
-
- # Media
- ExpiresByType audio/ogg "access plus 1 month"
- ExpiresByType image/gif "access plus 1 month"
- ExpiresByType image/jpeg "access plus 1 month"
- ExpiresByType image/png "access plus 1 month"
- ExpiresByType video/mp4 "access plus 1 month"
- ExpiresByType video/ogg "access plus 1 month"
- ExpiresByType video/webm "access plus 1 month"
-
- # Web feeds
- ExpiresByType application/atom+xml "access plus 1 hour"
- ExpiresByType application/rss+xml "access plus 1 hour"
-
- # Web fonts
- ExpiresByType application/font-woff "access plus 1 month"
- ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
- ExpiresByType application/x-font-ttf "access plus 1 month"
- ExpiresByType font/opentype "access plus 1 month"
- ExpiresByType image/svg+xml "access plus 1 month"
-
-
-
-# ------------------------------------------------------------------------------
-# | Filename-based cache busting |
-# ------------------------------------------------------------------------------
-
-# If you're not using a build process to manage your filename version revving,
-# you might want to consider enabling the following directives to route all
-# requests such as `/css/style.12345.css` to `/css/style.css`.
-
-# To understand why this is important and a better idea than `*.css?v231`, read:
-# http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring
-
-#
-# RewriteCond %{REQUEST_FILENAME} !-f
-# RewriteCond %{REQUEST_FILENAME} !-d
-# RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L]
-#
-
-# ------------------------------------------------------------------------------
-# | File concatenation |
-# ------------------------------------------------------------------------------
-
-# Allow concatenation from within specific CSS and JS files, e.g.:
-# Inside of `script.combined.js` you could have
-#
-#
-# and they would be included into this single file.
-
-#
-#
-# Options +Includes
-# AddOutputFilterByType INCLUDES application/javascript application/json
-# SetOutputFilter INCLUDES
-#
-#
-# Options +Includes
-# AddOutputFilterByType INCLUDES text/css
-# SetOutputFilter INCLUDES
-#
-#
-
-# ------------------------------------------------------------------------------
-# | Persistent connections |
-# ------------------------------------------------------------------------------
-
-# Allow multiple requests to be sent over the same TCP connection:
-# http://httpd.apache.org/docs/current/en/mod/core.html#keepalive.
-
-# Enable if you serve a lot of static content but, be aware of the
-# possible disadvantages!
-
-#
-# Header set Connection Keep-Alive
-#
diff --git a/app/404.html b/app/404.html
deleted file mode 100644
index fdace4a..0000000
--- a/app/404.html
+++ /dev/null
@@ -1,157 +0,0 @@
-
-
-
-
- Page Not Found :(
-
-
-
-
-
Not found :(
-
Sorry, but the page you were trying to view does not exist.
-
It looks like this was the result of either:
-
- a mistyped address
- an out-of-date link
-
-
-
-
-
-
diff --git a/app/favicon.ico b/app/favicon.ico
deleted file mode 100644
index a7ad21c..0000000
Binary files a/app/favicon.ico and /dev/null differ
diff --git a/app/images/configurations.png b/app/images/configurations.png
deleted file mode 100644
index 4127ec7..0000000
Binary files a/app/images/configurations.png and /dev/null differ
diff --git a/app/images/examples.png b/app/images/examples.png
deleted file mode 100644
index 5a70f0d..0000000
Binary files a/app/images/examples.png and /dev/null differ
diff --git a/app/images/glyphicons-halflings-white.png b/app/images/glyphicons-halflings-white.png
deleted file mode 100644
index 3bf6484..0000000
Binary files a/app/images/glyphicons-halflings-white.png and /dev/null differ
diff --git a/app/images/glyphicons-halflings.png b/app/images/glyphicons-halflings.png
deleted file mode 100644
index ab5686e..0000000
Binary files a/app/images/glyphicons-halflings.png and /dev/null differ
diff --git a/app/images/index-header.png b/app/images/index-header.png
deleted file mode 100644
index 54474ca..0000000
Binary files a/app/images/index-header.png and /dev/null differ
diff --git a/app/index.html b/app/index.html
deleted file mode 100644
index 64ac058..0000000
--- a/app/index.html
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/robots.txt b/app/robots.txt
deleted file mode 100644
index 9417495..0000000
--- a/app/robots.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-# robotstxt.org
-
-User-agent: *
diff --git a/app/scripts/app.js b/app/scripts/app.js
deleted file mode 100644
index 84ea7f6..0000000
--- a/app/scripts/app.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict';
-
-// App libraries
-var app = angular.module('oauth', [
- 'oauth.directive', // login directive
- 'oauth.accessToken', // access token service
- 'oauth.endpoint', // oauth endpoint service
- 'oauth.profile', // profile model
- 'oauth.interceptor' // bearer token interceptor
-])
-
-angular.module('oauth').config(['$locationProvider','$httpProvider',
- function($locationProvider, $httpProvider) {
- $locationProvider.html5Mode(true).hashPrefix('!'); // HTML5 mode
- $httpProvider.interceptors.push('OAuthInterceptor'); // Authentication header
- }]);
diff --git a/app/scripts/directives/oauth.js b/app/scripts/directives/oauth.js
deleted file mode 100644
index 54b6f28..0000000
--- a/app/scripts/directives/oauth.js
+++ /dev/null
@@ -1,98 +0,0 @@
-'use strict';
-
-var directives = angular.module('oauth.directive', []);
-
-directives.directive('oauth', ['AccessToken', 'Endpoint', 'Profile', '$location', '$rootScope', '$compile', '$http', '$templateCache',
- function(AccessToken, Endpoint, Profile, $location, $rootScope, $compile, $http, $templateCache) {
-
- var definition = {
- restrict: 'AE',
- replace: true,
- scope: {
- site: '@', // (required) set the oauth server host (e.g. http://oauth.example.com)
- clientId: '@', // (required) client id
- redirectUri: '@', // (required) client redirect uri
- scope: '@', // (optional) scope
- profileUri: '@', // (optional) user profile uri (e.g http://example.com/me)
- template: '@' // (optional) template to render (e.g views/templates/default.html)
- }
- };
-
- definition.link = function postLink(scope, element, attrs) {
- scope.show = 'none';
-
- scope.$watch('client', function(value) {
- init(); // sets defaults
- compile(); // compiles the desired layout
- Endpoint.set(scope); // sets the oauth authorization url
- AccessToken.set(scope); // sets the access token object (if existing, from fragment or session)
- initProfile(scope); // gets the profile resource (if existing the access token)
- initView(); // sets the view (logged in or out)
- });
-
- var init = function() {
- scope.authorizePath = scope.authorizePath || '/oauth/authorize';
- scope.tokenPath = scope.tokenPath || '/oauth/token';
- scope.template = scope.template || 'views/templates/default.html';
- }
-
- var compile = function() {
- $http.get(scope.template, { cache: $templateCache }).success(function(html) {
- element.html(html);
- $compile(element.contents())(scope);
- });
- };
-
- var initProfile = function(scope) {
- var token = AccessToken.get();
-
- if (token && token.access_token && scope.profileUri) {
- Profile.get(scope.profileUri).success(function(response) { scope.profile = response })
- }
- }
-
- var initView = function(token) {
- var token = AccessToken.get();
-
- if (!token) { return loggedOut() } // without access token it's logged out
- if (token.access_token) { return loggedIn() } // if there is the access token we are done
- if (token.error) { return denied() } // if the request has been denied we fire the denied event
- }
-
-
- scope.login = function() {
- Endpoint.redirect();
- }
-
- scope.logout = function() {
- AccessToken.destroy(scope);
- loggedOut();
- }
-
- // set the oauth directive to the logged-in status
- var loggedIn = function() {
- $rootScope.$broadcast('oauth:success', AccessToken.get());
- scope.show = 'logged-in';
- }
-
- // set the oauth directive to the logged-out status
- var loggedOut = function() {
- $rootScope.$broadcast('oauth:logout');
- scope.show = 'logged-out';
- }
-
- // set the oauth directive to the denied status
- var denied = function() {
- scope.show = 'denied';
- $rootScope.$broadcast('oauth:denied');
- }
-
- // Updates the template at runtime
- scope.$on('oauth:template:update', function(event, template) {
- scope.template = template;
- compile(scope);
- });
- };
-
- return definition
-}]);
diff --git a/app/scripts/interceptors/oauth-interceptor.js b/app/scripts/interceptors/oauth-interceptor.js
deleted file mode 100644
index 92485c0..0000000
--- a/app/scripts/interceptors/oauth-interceptor.js
+++ /dev/null
@@ -1,28 +0,0 @@
-'use strict';
-
-var service = angular.module('oauth.interceptor', []);
-
-service.factory('OAuthInterceptor', ['$rootScope', '$q', '$sessionStorage',
- function ($rootScope, $q, $sessionStorage) {
-
- var service = {};
-
- service.request = function(config) {
- var token = $sessionStorage.token;
-
- if (token)
- config.headers.Authorization = 'Bearer ' + token.access_token;
-
- if (token && expired(token))
- $rootScope.$broadcast('oauth:expired', token);
-
- return config;
- };
-
- var expired = function(token) {
- return (token && token.expires_at && new Date(token.expires_at) < new Date())
- }
-
- return service;
- }]);
-
diff --git a/app/scripts/services/access-token.js b/app/scripts/services/access-token.js
deleted file mode 100644
index e85bfbe..0000000
--- a/app/scripts/services/access-token.js
+++ /dev/null
@@ -1,151 +0,0 @@
-'use strict';
-
-var service = angular.module('oauth.accessToken', ['ngStorage']);
-
-service.factory('AccessToken', ['$rootScope', '$location', '$http', '$sessionStorage',
- function($rootScope, $location, $http, $sessionStorage) {
-
- var service = {};
- var token = null;
-
-
- /*
- * Returns the access token.
- */
-
- service.get = function() {
- return token
- }
-
-
- /*
- * Sets and returns the access token. It tries (in order) the following strategies:
- * - takes the token from the fragment URI
- * - takes the token from the sessionStorage
- */
-
- service.set = function() {
- setTokenFromString();
- setTokenFromSession();
- return token
- }
-
-
- /*
- * Delete the access token and remove the session.
- */
-
- service.destroy = function() {
- delete $sessionStorage.token;
- return token = null;
- }
-
-
- /*
- * Tells if the access token is expired.
- */
-
- service.expired = function() {
- return (token && token.expires_at && token.expires_at < new Date())
- }
-
-
-
- /* * * * * * * * * *
- * PRIVATE METHODS *
- * * * * * * * * * */
-
-
- /*
- * Get the access token from a string and save it
- */
-
- var setTokenFromString = function() {
- var token = getTokenFromString($location.hash());
-
- if (token) {
- removeFragment();
- setToken(token);
- }
- };
-
-
- /*
- * Parse the fragment URI and return an object
- */
-
- var getTokenFromString = function(hash) {
- var splitted = hash.split('&');
- var params = {};
-
- for (var i = 0; i < splitted.length; i++) {
- var param = splitted[i].split('=');
- var key = param[0];
- var value = param[1];
- params[key] = value
- }
-
- if (params.access_token || params.error)
- return params;
- }
-
-
- /*
- * Set the access token from the sessionStorage.
- */
-
- var setTokenFromSession = function() {
- if ($sessionStorage.token) {
- var params = $sessionStorage.token;
- setToken(params);
- }
- }
-
-
- /*
- * Save the access token into the session
- */
-
- var setTokenInSession = function() {
- $sessionStorage.token = token;
- }
-
-
- /*
- * Set the access token.
- */
-
- var setToken = function(params) {
- token = token || {} // init the token
- angular.extend(token, params); // set the access token params
- setExpiresAt(); // set the expiring time
- setTokenInSession(); // save the token into the session
- return token;
- };
-
-
- /*
- * Set the access token expiration date (useful for refresh logics)
- */
-
- var setExpiresAt = function() {
- if (token) {
- var expires_at = new Date();
- expires_at.setSeconds(expires_at.getSeconds() + parseInt(token.expires_in) - 60); // 60 seconds less to secure browser and response latency
- token.expires_at = expires_at;
- }
- };
-
-
- /*
- * Remove the fragment URI
- * TODO we need to remove only the access token
- */
-
- var removeFragment = function(scope) {
- $location.hash('');
- }
-
-
- return service;
-}]);
diff --git a/app/scripts/services/endpoint.js b/app/scripts/services/endpoint.js
deleted file mode 100644
index 71e3c94..0000000
--- a/app/scripts/services/endpoint.js
+++ /dev/null
@@ -1,48 +0,0 @@
-'use strict';
-
-var client = angular.module('oauth.endpoint', []);
-
-client.factory('Endpoint', ['AccessToken', '$location',
- function(AccessToken, $location) {
-
- var service = {};
- var params;
- var url;
-
-
- /*
- * Defines the authorization URL
- */
-
- service.set = function(scope) {
- url = scope.site +
- scope.authorizePath +
- '?response_type=token&' +
- 'client_id=' + scope.clientId + '&' +
- 'redirect_uri=' + scope.redirectUri + '&' +
- 'scope=' + scope.scope + '&' +
- 'state=' + $location.url()
-
- return url;
- }
-
-
- /*
- * Returns the authorization URL
- */
-
- service.get = function() {
- return url;
- }
-
-
- /*
- * Redirects the app to the authorization URL
- */
-
- service.redirect = function() {
- window.location.replace(url);
- }
-
- return service;
-}]);
diff --git a/app/scripts/services/profile.js b/app/scripts/services/profile.js
deleted file mode 100644
index e3f8062..0000000
--- a/app/scripts/services/profile.js
+++ /dev/null
@@ -1,13 +0,0 @@
-'use strict';
-
-var client = angular.module('oauth.profile', [])
-
-client.factory('Profile', ['$http', function($http) {
- var service = {}
-
- service.get = function(uri) {
- return $http.get(uri);
- }
-
- return service;
-}]);
diff --git a/app/styles/main.css b/app/styles/main.css
deleted file mode 100644
index 5db42e1..0000000
--- a/app/styles/main.css
+++ /dev/null
@@ -1,798 +0,0 @@
-/*
- * Lelylan Dev Center Documentation
- *
- * Table of contents:
- * - saas
- * - scaffolding
- * - top (contextual) navigation
- * - left navigation
- * - code sintax
- * - steps animations
- */
-
-$iconSpritePath: "../images/glyphicons-halflings.png";
-$iconWhiteSpritePath: "../images/glyphicons-halflings-white.png";
-
-/* import to override variables and to access the mixins */
-
-@import "http://github.com/bootstrap-sass/lib/bootstrap";
-
-/* variables */
-
-$lelylanColor: #BB234E;
-$lelylanHoverColor: #018DCF;
-$lelylanBackgroundColor: #009FC7;
-$linkColor: $lelylanColor;
-$linkColorHover: $lelylanHoverColor;
-
-/* mixins */
-
-@mixin box-shadow {
- $intensity: 0.2;
- -webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0,$intensity);
- -moz-box-shadow: 0px 1px 3px rgba(0, 0, 0,$intensity);
- box-shadow: 0px 1px 3px rgba(0, 0, 0, $intensity);
-}
-
-
-/* * * * * * * */
-/* Scaffolding */
-/* * * * * * * */
-
-/* body defaults */
-
-body {
- background-color: #f8f8f8 !important;
- padding-top: 100px; /* Account for fixed navbar */
- position: relative; /* For scrollyspy */
-}
-
-/* anchor positioning */
-
-h1[id] {
- border-top:120px solid transparent;
- margin-top:-120px;
- -webkit-background-clip:padding-box;
- -moz-background-clip:padding;
- background-clip:padding-box;
-}
-
-h2[id] {
- padding-top: 100px;
- margin-top: -90px;
-}
-
-h3[id] {
- border-top:100px solid transparent;
- margin-top:-100px !important;
- -webkit-background-clip:padding-box;
- -moz-background-clip:padding;
- background-clip:padding-box;
-}
-
-/* titles */
-
-.bs-title {
- background-color: $lelylanBackgroundColor;
- color: #fff;
- margin: 0;
- padding: 20px 60px;
-}
-
-.bs-title h1 {
- font-size: 48px;
- font-weight: 200;
-}
-
-.bs-title h4 {
- color: #9EDAE6;
- font-size: 22px;
- font-weight: 100;
- letter-spacing: 2px;
- text-transform: uppercase;
-}
-
-/* internal subtitles */
-
-.bs-docs-section {
- padding: 20px 60px 40px;
-
- h2 {
- color: $lelylanColor;
- font-size: 32px;
- margin-bottom: 20px;
- font-weight: 200;
- }
-
- h3 {
- font-size: 22px;
- margin: 30px 0 20px;
- font-weight: 200;
- }
-
- p,
- ul li {
- font-size: 17px;
- font-weight: 200;
- line-height: 1.6;
- }
-
- p {
- margin-bottom: 10px;
- }
-
- ul {
- margin-bottom: 20px;
- }
-}
-
-/* multiselection subtitles */
-
-.bs-title .nav-pills {
- margin-top: 20px;
-
- li {
- margin-right: 13px;
- }
-
- li a {
- background-color: #fff;
- border: none;
- border-radius: 0;
- color: $lelylanColor;
- }
-
- li.active a,
- li a:hover {
- background-color: $lelylanHoverColor;
- color: #fff !important;
- }
-}
-
-
-/* documentation page */
-
-.bs-docs {
- background-color: #fbfbfb;
- padding: 0;
- @include box-shadow;
-
- p a,
- table a,
- li a {
- color: $linkColor !important;
- }
-
- p a:hover,
- table a:hover,
- li a:hover {
- text-decoration: none;
- color: $linkColorHover !important;
- }
-}
-
-/* link colors animation */
-
-a {
- -webkit-transition: color 0.3s ease, text-decoration 0.3s ease, background 0.3s ease;
- -moz-transition: color 0.3s ease, text-decoration 0.3s ease, background 0.3s ease;
- transition: color 0.3s ease, text-decoration 0.3s ease, background 0.3s ease;
-}
-
-/* all blocks following the first one */
-
-.col-md-offset-3 {
- margin-top: 50px;
-}
-
-
-/* * * * * * * * * */
-/* Apps navigation */
-/* * * * * * * * * */
-
-/* lelylan apps navbar */
-
-.lelylan-navbar-apps {
- background-color: $lelylanBackgroundColor;
- border: none;
- height: 25px;
- min-height: 25px;
- margin-bottom: 0;
- margin-top: 0;
-
- .container {
- padding-left: 0;
- padding-right: 0
- }
-
- .navbar-nav > li > a {
- color: #40D4F0;
- font-size: 11px;
- padding: 2px 30px 0 0;
- text-shadow: 0 0 0 #333;
- text-transform: uppercase;
- }
-
- .navbar-nav > li > a:hover,
- .navbar-nav > li.active > a,
- .navbar-nav > li.active > a:hover {
- background-color: transparent;
- color: #eee;
- }
-
- .signout > a {
- text-transform: none !important;
- font-size: 12px !important;
- padding-right: 0 !important;
- font-weight: 200;
- }
-}
-
-
-/* * * * * * * * * */
-/* Top navigation */
-/* * * * * * * * * */
-
-/* Lelylan top menu navbar */
-
-.lelylan-navbar-top-menu {
- border: none;
- height: 50px;
- min-height: 50px;
- margin-bottom: 0;
- @include box-shadow;
-
- .container {
- padding-right: 0;
- }
-
- /* menu items */
-
- .navbar-nav > li > a {
- background-color: transparent;
- color: $linkColor !important;
- padding-right: 0;
- padding-left: 20px;
- font-weight: 200;
- font-size: 15px;
- }
-
- .navbar-nav > li > a:hover {
- color: $linkColorHover !important;
- }
-
- .navbar-nav > li > a.dropdown-toggle {
- padding-left: 50px;
- }
-
- .navbar-nav > li.active > a,
- .navbar-nav > li.active:hover > a,
- .navbar-nav > li.open > a,
- .navbar-nav > li.open > a.dropdown-toggle {
- background-color: transparent;
- }
-
- .navbar-nav > li.active > a {
- color: $lelylanHoverColor !important;
-
- }
-
- /* brand */
-
- .navbar-brand {
- font-size: 20px !important;
- //text-shadow: 0 1px 0 #eee;
- font-weight: 200;
- padding-left: 15px !important;
- color: #000 !important;
- }
-}
-
-
-/* * * * * * * * * */
-/* Left navigation */
-/* * * * * * * * * */
-
-/* By default it's not affixed in mobile views, so undo that */
-
-.bs-sidebar.affix {
- position: static;
-}
-
-/* First level of nav */
-
-.bs-sidenav {
- //background-color: #f8f8f8;
- margin-top: 30px;
- margin-bottom: 30px;
- padding-bottom: 10px;
- //@include box-shadow;
-}
-
-/* All levels of nav */
-
-.bs-sidebar .nav > li > a {
- color: $lelylanColor;
- display: block;
- font-size: 12px;
- padding: 5px 10px;
- text-transform: uppercase;
-}
-
-.bs-sidebar .nav > li > a:hover,
-.bs-sidebar .nav > li > a:focus {
- text-decoration: none;
- background-color: transparent;
- color: $lelylanHoverColor;
-}
-
-.bs-sidebar .nav > .active > a,
-.bs-sidebar .nav > .active:hover > a,
-.bs-sidebar .nav > .active:focus > a {
- //font-weight: bold;
- color: $lelylanHoverColor;
- background-color: transparent;
- border-left: 1px solid $lelylanHoverColor;
-}
-
-/* Nav: second level (shown on .active) */
-
-.bs-sidebar .nav .nav {
- display: none; /* Hide by default, but at >768px, show it */
- margin-bottom: 8px;
-}
-
-.bs-sidebar .nav .nav > li > a {
- padding-top: 3px;
- padding-bottom: 3px;
- padding-left: 25px;
- font-size: 12px;
- line-height: 1.6em;
- //text-transform: none;
-}
-
-/* Show and affix the side nav when space allows it */
-
-@media screen and (min-width: 992px) {
- .bs-sidebar .nav > .active > ul {
- display: block;
- }
- /* Widen the fixed sidebar */
- .bs-sidebar.affix,
- .bs-sidebar.affix-bottom {
- width: 213px;
- }
- .bs-sidebar.affix {
- position: fixed; /* Undo the static from mobile first approach */
- top: 100px;
- }
- .bs-sidebar.affix-bottom {
- position: absolute; /* Undo the static from mobile first approach */
- }
- .bs-sidebar.affix-bottom .bs-sidenav,
- .bs-sidebar.affix .bs-sidenav {
- margin-top: 0;
- margin-bottom: 0;
- }
-}
-
-/* Widen the fixed sidebar again */
-
-@media screen and (min-width: 1200px) {
- .bs-sidebar.affix-bottom,
- .bs-sidebar.affix {
- width: 263px;
- }
-}
-
-
-/* * * * * * * */
-/* Code syntax */
-/* * * * * * * */
-
-code {
- color: #111;
- background-color: transparent;
- font-size: 75%;
-}
-
-table code {
- font-size: 90%;
- padding-left: 0;
-}
-
-pre code,
-pre xmp {
- display:block;
- color:#111;
- font-family: Monaco, Consolas, monospace;
- font-size:12px;
- line-height:1.5;
- padding:5px;
- margin: 5px 3px;
-
- hr {
- margin: 15px 0 0;
- }
-}
-
-pre {
- margin: 0 0 40px;
- padding: 5px 0 5px 5px !important;
- background: #f8f8f8;
- border: 1px solid #ddd;
- border-radius: 0;
-}
-
-ul.nav-tabs,
-ol.nav-tabs {
- margin:15px 0 0 0;
- line-height:1.7em
-}
-
-ul.nav-tabs li.active a,
-ol.nav-tabs li.active a {
- background-color: #f8f8f8;
-}
-
-ul.nav-tabs {
- padding-left:0
-}
-
-div.tab-content pre {
- border-top:none
-}
-
-.nav-tabs > li > a {
- font-size: 16px;
- font-weight: 200;
-}
-
-.nav-tabs > li a {
- color: $linkColor;
-}
-
-.nav-tabs > li.active a:hover,
-.nav-tabs > li.active a {
- color: $linkColorHover;
- background-color: #f8f8f8;
-}
-
-.code-block {
- margin: 20px 0 30px;
-}
-
-
-/* * * * * * * * * */
-/* Animated steps */
-/* * * * * * * * * */
-
-.animation {
- max-width: 100%;
- background-color: #fff;
- padding: 0 15px 5px 20px;
- border: 1px solid #ddd;
- margin: 20px 0;
-
- h3 {
- display:inline;
- }
-
- p {
- float:clear;
- margin-top: 15px;
- margin-left: 6px;
- }
-
- pre {
- margin-left: 4px;
- }
-
- .button-lelylan {
- background-color: $lelylanColor;
- }
-
- .button-lelylan:hover {
- color: #fff;
- }
-
- .canvas {
- position:relative;
- width: 690px;
- height: 40px;
- margin: 20px 0 20px 0;
- }
-
- .action {
- padding-left: 5px;
- padding-bottom: 10px;
- }
-}
-
-
-/* * * * * * * * */
-/* Button style */
-/* * * * * * * * */
-
-.btn-lelylan {
- background: $lelylanColor;
- box-sizing: border-box;
- min-height: 35px;
- width: auto;
- display: inline-block;
- padding: 0.9em 1.37em;
- cursor: pointer;
- text-decoration: none;
- color: #fff;
- font-size: 12px;
- line-height: 13px;
- font-weight: 300;
- text-align: center;
- letter-spacing: 1px;
- text-transform: uppercase;
- text-shadow: none;
- border-radius: 0.2em;
- border: rgba(0,0,0,0.05) 0.1em solid;
- -webkit-transition: background 0.3s ease, border-color 0.3s ease;
- -moz-transition: background 0.3s ease, border-color 0.3s ease;
- transition: background 0.3s ease, border-color 0.3s ease;
-}
-
-.btn-lelylan:hover {
- background: $lelylanHoverColor;
- color: #fff;
- text-decoration: none;
-}
-
-.button-group {
- width: 390px;
- margin:0 auto;
- margin-bottom: 40px;
-
- a {
- font-size: 16px
- }
-}
-
-
-/* * * * * * * * */
-/* Table Listing */
-/* * * * * * * * */
-
-table {
- margin: 20px 0;
-
- tr th {
- border-bottom: 1px solid #dddddd !important;
- text-transform: uppercase;
- font-style: italic;
- }
-
- tr td,
- tr th {
- color: #333;
- font-size: 15px;
- font-weight: 200;
- line-height: 1.5 !important;
- }
-
- .parameter {
- width: 30%;
- }
-
- .extra {
- width: 30% !important;
- }
-
- .nested {
- padding-left: 30px !important;
- }
-
- .parameter span {
- font-style: italic;
- }
-
- span.info {
- display: block;
- color: #888;
- font-style: italic;
- }
-}
-
-.table-labeled {
-
- .label {
- padding: 0;
- }
-
- .label {
- border-radius: 2px;
- font-size: 12px;
- font-weight: 400;
- line-height: 23px;
- padding: 3px 6px 2px;
- text-transform: uppercase;
- background: #eee;
- border: 1px solid #ddd;
- color: #333;
- }
-
- .link {
- background: #E5F4FF;
- border: 1px solid #C5EAFF;
- }
-}
-
-
-
-
-/* * * * * * */
-/* Home Page */
-/* * * * * * */
-
-body.presentation {
- padding-top: 40px;
- background-color: #fbfbfb !important;
- text-rendering: optimizeLegibility;
-
- .lelylan-navbar-top-menu {
- background-color: #fbfbfb !important;
- }
-
- .presentation-block > .row {
- padding: 90px 0 60px;
- border-bottom: 1px solid #eee;
- }
-
- .banner {
- margin-top: 10px;
- height: 360px;
- //background: $lelylanColor url(http://github.com/images/index-header.png) center center;
- background-color: #333;
- color: #fff;
- background-size: cover;
- width: 100%;
- position: relative;
- border-bottom: 1px solid #ddd;
-
- .banner-content {
- padding: 120px 40px;
- font-weight: 300;
- }
-
- p, h1 {
- text-align: center;
- background: #000 !important;
- margin-bottom: 5px;
- margin-left: 25px;
- padding: 9px 15px 10px 20px;
- color: #FFF;
- }
-
- h1 {
- font-size: 68px;
- }
-
- p {
- font-size: 32px;
- font-weight: 100;
- }
-
- .banner-button {
- text-align: center;
-
- a {
- border: #ddd 0.1em solid;
- margin-top: 45px;
- height: 52px;
- font-size: 20px;
- font-weight: 100;
- letter-spacing: 2px;
- }
- }
-
- }
-
- h1 {
- font-size: 2.8em;
- border: none;
- padding: 0;
- margin: 0;
- margin-bottom: 35px;
- font-weight: 200;
- }
-
- h4 {
- color: #666;
- font-size: 16px;
- line-height: 26px;
- text-transform: uppercase;
- font-weight: 200;
- margin-bottom: 0;
- letter-spacing: 1px;
- }
-
- p {
- font-size: 18px;
- font-weight: 200;
- color: #333;
- margin-bottom: 35px;
- }
-
- .pull-left,
- .pull-right {
- padding-top: 20px;
- }
-
- p a {
- color: $linkColor;
- }
-
- p a:hover {
- text-decoration: none;
- color: $linkColorHover;
- }
-}
-
-/* detailed blocks */
-
-.bs-detailed h1 {
- font-size: 64px !important;
- font-weight: 200;
-}
-
-.bs-detailed h2 {
- margin-top: 40px;
- margin-bottom: 25px;
-}
-
-
-
-/* * * * * */
-/* Footer */
-/* * * * * */
-
-footer .bs-docs-section {
- padding-right: 0;
-
- a {
- color: $linkColor !important;
- }
- a:hover {
- text-decoration: none;
- color: $linkColorHover !important;
- }
-}
-
-
-
-/* * * * * * * * */
-/* Miscellaneous */
-/* * * * * * * * */
-
-.alert {
- padding: 10px;
-
- .label-lelylan {
- color: $lelylanColor;
- text-transform: uppercase;
- background-color: #fff;
- margin-right: 5px;
- font-weight: 400;
- padding: .3em .6em .2em;
- letter-spacing: 1px;
- }
-
- p {
- color: #3A3A3A;
- margin-bottom: 0;
- font-size: 16px;
- }
-}
-
-img {
- margin-top: 10px;
- margin-bottom: 30px;
- border-radius: 50%;
- border: 1px solid $lelylanColor;
-}
diff --git a/app/views/templates/button.html b/app/views/templates/button.html
deleted file mode 100644
index ce7861a..0000000
--- a/app/views/templates/button.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
- Login Button
- Logout {{profile.email}}
- Access denied.
-
diff --git a/app/views/templates/default.html b/app/views/templates/default.html
deleted file mode 100644
index 3591753..0000000
--- a/app/views/templates/default.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
- Sign In
- Logout {{profile.full_name}}
- Access denied. Try again.
-
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 0de5fcb..0000000
--- a/bower.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "oauth-ng",
- "version": "0.1.1-beta",
- "main": [
- "dist/oauth-ng.js",
- "dist/views/templates/default"
- ],
- "ignore": [
- "app",
- "test",
- "bower.json",
- "Gruntfile.js",
- "karma.conf.js",
- "package.json"
- ],
- "dependencies": {
- "angular": "~1.2.16",
- "ngstorage": "~0.3.0"
- },
- "devDependencies": {
- "json3": "~3.2.4",
- "es5-shim": "~2.0.8",
- "timecop": "~0.1.1",
- "bootstrap-sass": "~3.0.2",
- "jquery": "~1.9.1",
- "angular-mocks": "~1.2.16"
- }
-}
diff --git a/dist/ng-oauth.js b/dist/ng-oauth.js
deleted file mode 100644
index 79bda58..0000000
--- a/dist/ng-oauth.js
+++ /dev/null
@@ -1,361 +0,0 @@
-/* ng-oauth - v0.1.1 - 2014-05-20 */
-
-'use strict';
-
-// App libraries
-var app = angular.module('oauth', [
- 'oauth.directive', // login directive
- 'oauth.accessToken', // access token service
- 'oauth.endpoint', // oauth endpoint service
- 'oauth.profile', // profile model
- 'oauth.interceptor' // bearer token interceptor
-])
-
-angular.module('oauth').config(['$locationProvider','$httpProvider',
- function($locationProvider, $httpProvider) {
- $locationProvider.html5Mode(true).hashPrefix('!'); // HTML5 mode
- $httpProvider.interceptors.push('OAuthInterceptor'); // Authentication header
- }]);
-
-'use strict';
-
-var directives = angular.module('oauth.directive', []);
-
-directives.directive('oauth', ['AccessToken', 'Endpoint', 'Profile', '$location', '$rootScope', '$compile', '$http', '$templateCache',
- function(AccessToken, Endpoint, Profile, $location, $rootScope, $compile, $http, $templateCache) {
-
- var definition = {
- restrict: 'AE',
- replace: true,
- scope: {
- site: '@', // (required) set the oauth server host (e.g. http://oauth.example.com)
- clientId: '@', // (required) client id
- redirectUri: '@', // (required) client redirect uri
- scope: '@', // (optional) scope
- profileUri: '@', // (optional) user profile uri (e.g http://example.com/me)
- template: '@' // (optional) template to render (e.g bower_components/oauth-ng/dist/views/templates/default.html)
- }
- };
-
- definition.link = function postLink(scope, element, attrs) {
- scope.show = 'none';
-
- scope.$watch('client', function(value) {
- init(); // sets defaults
- compile(); // compiles the desired layout
- Endpoint.set(scope); // sets the oauth authorization url
- AccessToken.set(scope); // sets the access token object (if existing, from fragment or session)
- initProfile(scope); // gets the profile resource (if existing the access token)
- initView(); // sets the view (logged in or out)
- });
-
- var init = function() {
- scope.authorizePath = scope.authorizePath || '/oauth/authorize';
- scope.tokenPath = scope.tokenPath || '/oauth/token';
- scope.template = scope.template || 'bower_components/oauth-ng/dist/views/templates/default.html';
- }
-
- var compile = function() {
- $http.get(scope.template, { cache: $templateCache }).success(function(html) {
- element.html(html);
- $compile(element.contents())(scope);
- });
- };
-
- var initProfile = function(scope) {
- var token = AccessToken.get();
-
- if (token && token.access_token && scope.profileUri) {
- Profile.get(scope.profileUri).success(function(response) { scope.profile = response })
- }
- }
-
- var initView = function(token) {
- var token = AccessToken.get();
-
- if (!token) { return loggedOut() } // without access token it's logged out
- if (token.access_token) { return loggedIn() } // if there is the access token we are done
- if (token.error) { return denied() } // if the request has been denied we fire the denied event
- }
-
-
- scope.login = function() {
- Endpoint.redirect();
- }
-
- scope.logout = function() {
- AccessToken.destroy(scope);
- loggedOut();
- }
-
- // set the oauth directive to the logged-in status
- var loggedIn = function() {
- $rootScope.$broadcast('oauth:success', AccessToken.get());
- scope.show = 'logged-in';
- }
-
- // set the oauth directive to the logged-out status
- var loggedOut = function() {
- $rootScope.$broadcast('oauth:logout');
- scope.show = 'logged-out';
- }
-
- // set the oauth directive to the denied status
- var denied = function() {
- scope.show = 'denied';
- $rootScope.$broadcast('oauth:denied');
- }
-
- // Updates the template at runtime
- scope.$on('oauth:template:update', function(event, template) {
- scope.template = template;
- compile(scope);
- });
- };
-
- return definition
-}]);
-
-'use strict';
-
-var service = angular.module('oauth.interceptor', []);
-
-service.factory('OAuthInterceptor', ['$rootScope', '$q', '$sessionStorage',
- function ($rootScope, $q, $sessionStorage) {
-
- var service = {};
-
- service.request = function(config) {
- var token = $sessionStorage.token;
-
- if (token)
- config.headers.Authorization = 'Bearer ' + token.access_token;
-
- if (token && expired(token))
- $rootScope.$broadcast('oauth:expired', token);
-
- return config;
- };
-
- var expired = function(token) {
- return (token && token.expires_at && new Date(token.expires_at) < new Date())
- }
-
- return service;
- }]);
-
-
-'use strict';
-
-var service = angular.module('oauth.accessToken', ['ngStorage']);
-
-service.factory('AccessToken', ['$rootScope', '$location', '$http', '$sessionStorage',
- function($rootScope, $location, $http, $sessionStorage) {
-
- var service = {};
- var token = null;
-
-
- /*
- * Returns the access token.
- */
-
- service.get = function() {
- return token
- }
-
-
- /*
- * Sets and returns the access token. It tries (in order) the following strategies:
- * - takes the token from the fragment URI
- * - takes the token from the sessionStorage
- */
-
- service.set = function() {
- setTokenFromString();
- setTokenFromSession();
- return token
- }
-
-
- /*
- * Delete the access token and remove the session.
- */
-
- service.destroy = function() {
- delete $sessionStorage.token;
- return token = null;
- }
-
-
- /*
- * Tells if the access token is expired.
- */
-
- service.expired = function() {
- return (token && token.expires_at && token.expires_at < new Date())
- }
-
-
-
- /* * * * * * * * * *
- * PRIVATE METHODS *
- * * * * * * * * * */
-
-
- /*
- * Get the access token from a string and save it
- */
-
- var setTokenFromString = function() {
- var token = getTokenFromString($location.hash());
-
- if (token) {
- removeFragment();
- setToken(token);
- }
- };
-
-
- /*
- * Parse the fragment URI and return an object
- */
-
- var getTokenFromString = function(hash) {
- var splitted = hash.split('&');
- var params = {};
-
- for (var i = 0; i < splitted.length; i++) {
- var param = splitted[i].split('=');
- var key = param[0];
- var value = param[1];
- params[key] = value
- }
-
- if (params.access_token || params.error)
- return params;
- }
-
-
- /*
- * Set the access token from the sessionStorage.
- */
-
- var setTokenFromSession = function() {
- if ($sessionStorage.token) {
- var params = $sessionStorage.token;
- setToken(params);
- }
- }
-
-
- /*
- * Save the access token into the session
- */
-
- var setTokenInSession = function() {
- $sessionStorage.token = token;
- }
-
-
- /*
- * Set the access token.
- */
-
- var setToken = function(params) {
- token = token || {} // init the token
- angular.extend(token, params); // set the access token params
- setExpiresAt(); // set the expiring time
- setTokenInSession(); // save the token into the session
- return token;
- };
-
-
- /*
- * Set the access token expiration date (useful for refresh logics)
- */
-
- var setExpiresAt = function() {
- if (token) {
- var expires_at = new Date();
- expires_at.setSeconds(expires_at.getSeconds() + parseInt(token.expires_in) - 60); // 60 seconds less to secure browser and response latency
- token.expires_at = expires_at;
- }
- };
-
-
- /*
- * Remove the fragment URI
- * TODO we need to remove only the access token
- */
-
- var removeFragment = function(scope) {
- $location.hash('');
- }
-
-
- return service;
-}]);
-
-'use strict';
-
-var client = angular.module('oauth.endpoint', []);
-
-client.factory('Endpoint', ['AccessToken', '$location',
- function(AccessToken, $location) {
-
- var service = {};
- var params;
- var url;
-
-
- /*
- * Defines the authorization URL
- */
-
- service.set = function(scope) {
- url = scope.site +
- scope.authorizePath +
- '?response_type=token&' +
- 'client_id=' + scope.clientId + '&' +
- 'redirect_uri=' + scope.redirectUri + '&' +
- 'scope=' + scope.scope + '&' +
- 'state=' + $location.url()
-
- return url;
- }
-
-
- /*
- * Returns the authorization URL
- */
-
- service.get = function() {
- return url;
- }
-
-
- /*
- * Redirects the app to the authorization URL
- */
-
- service.redirect = function() {
- window.location.replace(url);
- }
-
- return service;
-}]);
-
-'use strict';
-
-var client = angular.module('oauth.profile', [])
-
-client.factory('Profile', ['$http', function($http) {
- var service = {}
-
- service.get = function(uri) {
- return $http.get(uri);
- }
-
- return service;
-}]);
diff --git a/dist/ng-oauth.min.js b/dist/ng-oauth.min.js
deleted file mode 100644
index c7e596e..0000000
--- a/dist/ng-oauth.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/* ng-oauth - v0.1.1 - 2014-05-20 */
-"use strict";var app=angular.module("oauth",["oauth.directive","oauth.accessToken","oauth.endpoint","oauth.profile","oauth.interceptor"]);angular.module("oauth").config(["$locationProvider","$httpProvider",function(a,b){a.html5Mode(!0).hashPrefix("!"),b.interceptors.push("OAuthInterceptor")}]);var directives=angular.module("oauth.directive",[]);directives.directive("oauth",["AccessToken","Endpoint","Profile","$location","$rootScope","$compile","$http","$templateCache",function(a,b,c,d,e,f,g,h){var i={restrict:"AE",replace:!0,scope:{site:"@",clientId:"@",redirectUri:"@",scope:"@",profileUri:"@",template:"@"}};return i.link=function(d,i){d.show="none",d.$watch("client",function(){j(),k(),b.set(d),a.set(d),l(d),m()});var j=function(){d.authorizePath=d.authorizePath||"/oauth/authorize",d.tokenPath=d.tokenPath||"/oauth/token",d.template=d.template||"bower_components/oauth-ng/dist/views/templates/default.html"},k=function(){g.get(d.template,{cache:h}).success(function(a){i.html(a),f(i.contents())(d)})},l=function(b){var d=a.get();d&&d.access_token&&b.profileUri&&c.get(b.profileUri).success(function(a){b.profile=a})},m=function(b){var b=a.get();return b?b.access_token?n():b.error?p():void 0:o()};d.login=function(){b.redirect()},d.logout=function(){a.destroy(d),o()};var n=function(){e.$broadcast("oauth:success",a.get()),d.show="logged-in"},o=function(){e.$broadcast("oauth:logout"),d.show="logged-out"},p=function(){d.show="denied",e.$broadcast("oauth:denied")};d.$on("oauth:template:update",function(a,b){d.template=b,k(d)})},i}]);var service=angular.module("oauth.interceptor",[]);service.factory("OAuthInterceptor",["$rootScope","$q","$sessionStorage",function(a,b,c){var d={};d.request=function(b){var d=c.token;return d&&(b.headers.Authorization="Bearer "+d.access_token),d&&e(d)&&a.$broadcast("oauth:expired",d),b};var e=function(a){return a&&a.expires_at&&new Date(a.expires_at)
- Login Button
- Logout {{profile.email}}
- Access denied.
-
diff --git a/dist/views/templates/default.html b/dist/views/templates/default.html
deleted file mode 100644
index 3591753..0000000
--- a/dist/views/templates/default.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
- Sign In
- Logout {{profile.full_name}}
- Access denied. Try again.
-
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..4b764e8
--- /dev/null
+++ b/index.html
@@ -0,0 +1,981 @@
+
+
+
+ oauth-ng | AngularJS directive for OAuth 2.0
+
+
+
+
+
+
+
+
+
+
+
+
oauth-ng
+
AngularJS directive for OAuth 2.0
+
+ See on Github
+
+
+
+
+
+
+
+
+
+
Getting Started
+
+
Installation
+
+
+ Install oauth-ng using Bower
+
+
+
$ bower install oauth-ng --save
+
+
Basic Example
+
+
+ This example shows you how the directive works.
+
+
+
+
+
+
+
+
+
+
+ To fully understand how it works read the next section .
+
+
+
+
What does it do?
+
+
+ It renders a Login link that lets you authorize a third party app through OAuth 2.0.
+ When the flow is completed, the access token is saved in the SessionStorage .
+
+
+
+
+
+
+
+
+
+
+
Create your first app with oauth-ng
+
+ In this section you will learn how to use the directive to authorize an OAuth 2.0 server
+ through the creation of a real project. It will take less than 10 minutues.
+
+
+
+ View Demo
+ Download Source
+
+
+
+
Setup
+
+
+ To build our app we'll use Yeoman , a collection of tools
+ and frameworks helping developers to quickly build web applications.
+
+
+
+
+ yo - perform ripetitive tasks.
+
+
+ grunt - build, preview and test your project.
+
+
+ bower - solve the frontend package management.
+
+
+
+
+
Installation
+
+
+ With a recent version of Node.js installed, install the yo
package.
+ In this way you have Yo, Grunt and Bower and can run them directly from the command-line.
+
+
+
$ npm install -g yo
+
+
+ With Yeoman you can install additional generators with npm. For this tutorial you need
+ to install the AngularJS generator.
+
+
+
$ npm install -g generator-angular
+
+
+
Create your AngularJS app
+
+
+ To begin, go to the terminal, make a new directory and cd into it.
+
+
+
$ mkdir new-project && cd $_
+
+
+ You can now kick-start your AngularJS app.
+
+
+
$ yo angular
+
+
+ It will also ask you if you would like to include Twitter Bootstrap and other stuff.
+ Once you've decided, just hit Enter. It will take a while to complete.
+
+
+
+ To preview what the app looks like run the serve command.
+
+
+
$ grunt serve
+
+
+ The server supports LiveReload, meaning you can fire up a text editor, edit a custom
+ element and the browser will reload on save.
+
+
+
+
Install oauth-ng
+
+
+ Install oauth-ng using Bower .
+
+
+
$ bower install oauth-ng --save
+
+
+ Now you have oauth-ng
and all its dependencies ready to be used.
+ Restart the server to automatically add them to your index page.
+
+
+
$ grunt serve
+
+
+ The setup is now completed.
+
+
+
+
AngularJS app definition
+
+
+ Inject the oauth-ng module into your application.
+
+
+
// app/scripts/app.js
+angular.module('newProjectApp', ['oauth', ... ])
+
+
Activate the HTML5 mode
+
+
+ Activate the HTML5 mode to catch the access token.
+
+
+
// app/scripts/app.js
+angular.module('newProjectApp').config(function($locationProvider) {
+ $locationProvider.html5Mode(true).hashPrefix('!');
+});
+
+
OAuth 2.0 Server
+
+
+ To test the directive we created a basic OAuth 2.0 authorization server at the address
+ http://oauth-ng-server.herokuapp.com
.
+
+
+
+
Identify your application
+
+
+ To make the directive work you need a registered application to get its
+ client-id
and redirect-uri
. For this example we
+ created a demo app with the following credentials.
+
+
+
+ client-id - 017b9f702a904869a6e52bd39b147bb912
+ redirect-uri - http://localhost:9000
+
+
+
+
Add the oauth-ng directive
+
+
+ Open your main.html view and place the oauth
tag with the needed configurations.
+
+
+
+
+
+
+ Here a description for what these settings are about.
+
+
+
+
+
+
+ site
+
+
+ OAuth 2.0 authorization server URI.
+
+
+
+
+ client-id
+
+
+ Registered Client ID.
+
+
+
+
+ redirect-uri
+
+
+ Registered application URI. Where the user is redirected after the authorization.
+
+
+
+
+ profile-uri
+
+
+ API endpoint to get the authenticated profile resource.
+
+
+
+
+ scope
+
+
+ Application privileges to be requested from the authorization server. The value should be in plain text and will be properly URI encoded for authorization.
+
+
+
+
+
+
+
You're done!
+
+
+ Open your index page, click to the Login link and authorize your application
+ to get a new access token. You are now ready to access your API using OAuth
+ 2.0 and AngularJS.
+
+
+
+ View Demo
+ Download Source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
HTML5 mode
+
+
+
HTML5 mode ON
+
+
The oauth directive works just straight when the HTML5 mode is active.
+
+
+
+
+
HTML5 mode OFF
+
+
+ When the HTML5 mode is off (default setup on AngularJS) add the following
+ snippet of code to your routing provider.
+
+
+
angular.module('app').config(function ($routeProvider) {
+ $routeProvider
+ .when('/access_token=:accessToken', {
+ template: '',
+ controller: function ($location, AccessToken) {
+ var hash = $location.path().substr(1);
+ AccessToken.setTokenFromString(hash);
+ $location.path('/');
+ $location.replace();
+ }
+ })
+ ...
+
+
+
+ This code is needed because the fragment that the OAuth 2.0 server returns is recognized
+ as the routing path /access_token
. For this reason you need to add a routing
+ rule catching the access token, parse it and then redirect to the desired view of your app.
+
+
+
+
+
+
+
+
+
Configurations
+
+
+ The directive accepts the following attributes.
+
+
+
+
+
+
+ site
+ required
+
+
+ A string that represents the authorization endpoint.
+
+
+
+
+ client-id
+ required
+
+
+ Registered Client ID.
+
+
+
+
+ response-type
+ required
+
+
+ Default to token
, which is for OAuth 2.0 implicit grant type. To use OpenID Connect Implicit Flow,
+ use id_token
(to get id_token only) or id_token token
(to get both id_token and access_token)
+
+
+
+
+ redirect-uri
+ required
+
+
+ Registered application URI where the user is redirected after the authorization.
+
+
+
+
+ scope
+ optional
+
+
+ Application privileges to be requested from the authorization server. The value should be in plain text and will be properly URI encoded for authorization.
+ When using OpenID Connect Implicit Flow, value openid
must be included.
+
+
+
+
+ profile-uri
+ optional
+
+
+ API endpoint returning the authenticated profile resource.
+
+
+
+
+ state
+ optional
+
+
+ An arbitrary unique string created by your app to guard against Cross-site Request Forgery .
+
+
+
+
+ template
+ optional
+
+
+ Custom template you want to render.
+ Default to default.html
.
+
+
+
+
+ authorize-path
+ optional
+
+
+ Authorization URL for the OAuth2 Implicit Flow.
+ Default to /oauth/authorize
.
+
+
+
+
+ text
+ optional
+
+
+ Visible text when the user has to login.
+ Default to Sign in
.
+
+
+
+
+ storage
+ (optional)
+
+
+ How the token is stored locally,
+ localStorage
or sessionStorage
.
+ Defaults to sessionStorage
.
+
+
+
+
+ issuer
+ (optional)
+
+
+ For OpenID Connect Implicit Flow only.
+ The issuer of the id_token. It must exactly match the iss
claim (if exists) in the id_token
+
+
+
+
+ subject
+ (optional)
+
+
+ For OpenID Connect Implicit Flow only.
+ The subject of the id_token. The detailed meaning is usually application specific.
+ It must exactly match the sub
claim (if exists) in the id_token
+
+
+
+
+ pub-key
+ (optional)
+
+
+ For OpenID Connect Implicit Flow only.
+ The public key to verify the id_token signature. It could be .pem
format or JWK format.
+ For signing algorithm (usually specified by alg
in the id_token header), currently only RS256
, RS384
, or RS512
is supported.
+ If not set, then the id_token itself should carry the public key, or the url which can be used to retrieve the public key.
+
+
+
+
+
+
+
+
+
+
+
+
Customizations
+
+
+ The oauth directive comes to life with customization in mind. You can easily define
+ personalized CSS styles or create brand new templates.
+
+
+
Custom CSS
+
+
+ By default the directive is shown as a simple link. To improve its visual style
+ add some CSS rules.
+
+
+
+
+
+
+
+ All CSS rules applies to the following HTML structure.
+
+
+
+ Sign In
+ Logout Alice
+ Access denied. Try again.
+
+
+
+ It's easy to create your own. Base all of your rules on the oauth
class
+ or checkout existing CSS definitions to better understand how it works
+ (e.g. the blue button CSS ).
+
+
+
+ Mail or Tweet
+ me if you make new CSS buttons so that we can add them do the docs.
+
+
+
+
Custom Template
+
+
+ When the custom template does not satisfy your needs (e.g. you want to show the user email
+ when logged in), you can create a new one. To have an idea of what a template looks like,
+ see the code below (related to the default template).
+
+
+
+ {{text}}
+ Logout {{profile.email}}
+ Access denied. Try again.
+
+
+
+ To create your new template, define the HTML and make it work using the following internal API.
+
+
+
+
+
+
+ show
+ variable
+
+
+ Defines the oauth status.
+ Valid values are logged-out
, logged-in
and denied
.
+
+
+
+
+ text
+ variable
+
+
+ Visible text when the widget is logged out.
+ Default to Sign in
.
+
+
+
+
+ login()
+ method
+
+
+ Logs in redirecting the app to the OAuth 2.0 authorization server.
+
+
+
+
+ logout()
+ method
+
+
+ Logs out deleting the access token.
+
+
+
+
+
+
+ Now, supposing you have defined a new template in views/templates/custom.html
,
+ you need to let the directive know about its existence. You can do this in two ways.
+
+
+
+ Setting the template attribute
+ Firing the template event
+
+
+
1 - Template attribute
+
+
+ Set the template path (or uri) as value for the template attribute.
+
+
+
+
+
+
2 - Template event
+
+
+ Fires the update template event passing the template path (or uri) as param.
+
+
+
$rootScope.$broadcast('oauth:template:update', 'views/templates/custom.html');
+
+
+ Use this solution when you need to update the directive at runtime. For all
+ other cases, use the template attribute.
+
+
+
+
+
+
+
+
+
Events
+
+
+ The events related to the oauth directive are the following.
+
+
+
+
+
+
+ oauth:login(token)
+ fired
+
+
+ Fired when the user has completed the login flow, and authorized the third party app.
+
+
+
+
+ oauth:authorized(token)
+ fired
+
+
+ Fired when the view is initializing and user has a non-expired auth token in the local session storage.
+
+
+
+
+ oauth:logout
+ fired
+
+
+ Fired when the user logs out.
+
+
+
+
+ oauth:loggedOut
+ fired
+
+
+ Fired when the user is not logged in.
+
+
+
+
+ oauth:denied
+ fired
+
+
+ Fired when the user denies the access to the third party app.
+
+
+
+
+ oauth:expired
+ fired
+
+
+ Fired when the access token is expired.
+
+
+
+
+ oauth:template:update(uri)
+ listening
+
+
+ Listening for runtime the template change.
+ See examples in the customization section.
+
+
+
+
+ oauth:profile(profile)
+ fired
+
+
+ Fired when the profile data has been retrieved.
+ Does not fire if there is no profile-uri
parameter.
+
+
+
+
+
+
+ Here some examples.
+
+
+
$scope.$on('oauth:login', function(event, token) {
+ console.log('Authorized third party app with token', token.access_token);
+});
+
+$scope.$on('oauth:logout', function(event) {
+ console.log('The user has signed out');
+});
+
+$scope.$on('oauth:loggedOut', function(event) {
+ console.log('The user is not signed in');
+});
+
+$scope.$on('oauth:denied', function(event) {
+ console.log('The user did not authorize the third party app');
+});
+
+$scope.$on('oauth:expired', function(event) {
+ console.log('The access token is expired. Please refresh.');
+});
+
+$scope.$on('oauth:profile', function(profile) {
+ console.log('User profile data retrieved: ', profile);
+});
+
+
+
+
+
+
+
+
+
Logged in or logged out?
+
+
+ Inject the AccessToken.get()
service to understand if the user is logged in or out.
+
+
+
$timeout(function() {
+ $scope.logged = !!AccessToken.get();
+}, 0)
+
+
+ The AccessToken.get()
method returns null
when the user is logged
+ out and the access token representation when the user is logged in (see below).
+
+
+
+
{
+ "access_token": "9ce03e06f037180c2dcfa8b278217eb56d747730c69xxx",
+ "token_type": "bearer",
+ "expires_in": 7200,
+ "state": "remember-me"
+}
+
+
+
+
+
+
+
+
Profile resource
+
+
+ When a user signs in, the profile is accessible through the Profile
service.
+
+
+
$scope.profile = Profile.get();
+
+
+ This profile is accessible only when the profile-uri
attribute is defined and
+ it sets the Authorization header with the access token to authenticate the request.
+
+
+
Authorization:Bearer {token}
+
+
+
+
+
+
+
+
+
+
+
Thanks
+
+
+ Mail or
+ Tweet
+ me for any idea that can improve the project.
+
+
+
+ This project was created and released as open-source thanks to Lelylan ,
+ a new platform to monitor and control your devices through a simple, open and robust REST API.
+
+
+
+ If you like what I'm doing offer me a coffe
+
+
+
+
+
+
+
diff --git a/karma.conf.js b/karma.conf.js
deleted file mode 100644
index 28aab8c..0000000
--- a/karma.conf.js
+++ /dev/null
@@ -1,64 +0,0 @@
-// Karma configuration
-// http://karma-runner.github.io/0.10/config/configuration-file.html
-
-module.exports = function(config) {
- config.set({
- // base path, that will be used to resolve files and exclude
- basePath: '',
-
- // testing framework to use (jasmine/mocha/qunit/...)
- frameworks: ['jasmine'],
-
- // list of files / patterns to load in the browser
- files: [
- 'app/bower_components/jquery/jquery.js',
- 'app/bower_components/angular/angular.js',
- 'app/bower_components/angular-mocks/angular-mocks.js',
- 'app/bower_components/ngstorage/ngStorage.js',
- 'app/bower_components/timecop/timecop-0.1.1.js',
- 'app/scripts/*.js',
- 'app/scripts/**/*.js',
- 'app/views/**/*.html',
- 'test/spec/services/**/*.js',
- 'test/spec/directives/**/*.js'
- ],
-
- // list of files / patterns to exclude
- exclude: [],
-
- // web server port
- port: 8080,
-
- // level of logging
- // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
- logLevel: config.LOG_INFO,
-
- // enable / disable watching file and executing tests whenever any file changes
- autoWatch: true,
-
- // Start these browsers, currently available:
- // - Chrome
- // - ChromeCanary
- // - Firefox
- // - Opera
- // - Safari (only Mac)
- // - PhantomJS
- // - IE (only Windows)
- browsers: ['PhantomJS'],
-
- // Continuous Integration mode
- // if true, it capture browsers, run tests and exit
- singleRun: false,
-
-
- // Preprocessor for converting HTML files to AngularJS templates
- preprocessors: { 'app/views/**/*.html': ['html2js'] },
-
- // set the path to use to search the template and set the templates module to
- // load all templates at once
- ngHtml2JsPreprocessor: {
- stripPrefix: 'app/',
- moduleName: 'templates'
- },
- });
-};
diff --git a/package.json b/package.json
deleted file mode 100644
index fb41b7b..0000000
--- a/package.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "name": "oauth-ng",
- "version": "0.1.0",
- "author": "Andrea Reginato ",
- "description": "AngularJS Directive for OAuth 2.0",
- "repository": {
- "type": "git",
- "url": "https://github.com/andreareginato/oauth-ng"
- },
- "dependencies": {},
- "devDependencies": {
- "grunt": "~0.4.1",
- "grunt-autoprefixer": "~0.4.0",
- "grunt-bower-install": "~0.7.0",
- "grunt-concurrent": "~0.4.1",
- "grunt-contrib-clean": "~0.5.0",
- "grunt-contrib-coffee": "~0.7.0",
- "grunt-contrib-compass": "~0.6.0",
- "grunt-contrib-concat": "~0.3.0",
- "grunt-contrib-connect": "~0.5.0",
- "grunt-contrib-copy": "~0.4.1",
- "grunt-contrib-cssmin": "~0.7.0",
- "grunt-contrib-htmlmin": "~0.1.3",
- "grunt-contrib-imagemin": "~0.3.0",
- "grunt-contrib-jshint": "~0.7.1",
- "grunt-contrib-uglify": "~0.2.0",
- "grunt-contrib-watch": "~0.5.2",
- "grunt-google-cdn": "~0.2.0",
- "grunt-newer": "~0.5.4",
- "grunt-ngmin": "~0.0.2",
- "grunt-rev": "~0.1.0",
- "grunt-svgmin": "~0.2.0",
- "grunt-usemin": "~2.0.0",
- "jshint-stylish": "~0.1.3",
- "load-grunt-tasks": "~0.2.0",
- "time-grunt": "~0.2.1",
- "karma-ng-scenario": "~0.1.0",
- "grunt-karma": "~0.8.0",
- "karma": "~0.12.0",
- "karma-ng-html2js-preprocessor": "~0.1.0",
- "karma-jasmine": "~0.2.2",
- "karma-phantomjs-launcher": "~0.1.2",
- "karma-chrome-launcher": "~0.1.2",
- "karma-coverage": "~0.2.1",
- "grunt-protractor-runner": "~0.2.4",
- "grunt-replace": "~0.7.7",
- "grunt-string-replace": "~0.2.7"
- },
- "engines": {
- "node": ">=0.8.0"
- },
- "scripts": {
- "test": "grunt test:unit"
- }
-}
diff --git a/public/icons/LICENSE.txt b/public/icons/LICENSE.txt
new file mode 100644
index 0000000..21877ea
--- /dev/null
+++ b/public/icons/LICENSE.txt
@@ -0,0 +1,21 @@
+Font license info
+
+
+## Font Awesome
+
+ Copyright (C) 2012 by Dave Gandy
+
+ Author: Dave Gandy
+ License: SIL ()
+ Homepage: http://fortawesome.github.com/Font-Awesome/
+
+
+## Typicons
+
+ (c) Stephen Hutchings 2012
+
+ Author: Stephen Hutchings
+ License: CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/)
+ Homepage: http://typicons.com/
+
+
diff --git a/public/icons/README.txt b/public/icons/README.txt
new file mode 100644
index 0000000..43e23f2
--- /dev/null
+++ b/public/icons/README.txt
@@ -0,0 +1,75 @@
+This webfont is generated by http://fontello.com open source project.
+
+
+================================================================================
+Please, note, that you should obey original font licences, used to make this
+webfont pack. Details available in LICENSE.txt file.
+
+- Usually, it's enough to publish content of LICENSE.txt file somewhere on your
+ site in "About" section.
+
+- If your project is open-source, usually, it will be ok to make LICENSE.txt
+ file publically available in your repository.
+
+- Fonts, used in Fontello, don't require to make clickable links on your site.
+ But any kind of additional authors crediting is welcome.
+================================================================================
+
+
+Comments on archive content
+---------------------------
+
+- /font/* - fonts in different formats
+
+- /css/* - different kinds of css, for all situations. Should be ok with
+ twitter bootstrap. Also, you can skip style and assign icon classes
+ directly to text elements, if you don't mind about IE7.
+
+- demo.html - demo file, to show your webfont content
+
+- LICENSE.txt - license info about source fonts, used to build your one.
+
+- config.json - keeps your settings. You can import it back to fontello anytime,
+ to continue your work
+
+
+Why so many CSS files ?
+-----------------------
+
+Because we like to fit all your needs :)
+
+- basic file, .css - is usually enougth, in contains @font-face
+ and character codes definition
+
+- *-ie7.css - if you need IE7 support, but still don't wish to put char codes
+ directly into html
+
+- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face
+ rules, but still wish to benefit of css generation. That can be very
+ convenient for automated assets build systems. When you need to update font -
+ no needs to manually edit files, just override old version with archive
+ content. See fontello source codes for example.
+
+- *-embedded.css - basic css file, but with embedded WOFF font, to avoid
+ CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain.
+ We strongly recommend to resolve this issue by `Access-Control-Allow-Origin`
+ server headers. But if you ok with dirty hack - this file is for you. Note,
+ that data url moved to separate @font-face to avoid problems with
+
+
+
+
+
+
+
+
+
+
+
+
icon-cancel 0xe803
+
icon-menu-1 0xe811
+
icon-plus 0xe804
+
icon-plus-circled 0xe805
+
+
+
icon-minus 0xe800
+
icon-minus-circled 0xe806
+
icon-attention-alt 0xe809
+
icon-attention 0xe808
+
+
+
icon-attention-circled 0xe80a
+
icon-cancel-circled 0xe802
+
icon-cog 0xe807
+
icon-resize-full 0xe810
+
+
+
icon-signal 0xe80b
+
icon-smile 0xe80c
+
icon-frown 0xe80d
+
icon-meh 0xe80e
+
+
+
icon-github 0xe80f
+
icon-menu 0xe801
+
+
+
+
+
\ No newline at end of file
diff --git a/public/icons/font/slate.eot b/public/icons/font/slate.eot
new file mode 100644
index 0000000..2f3f7be
Binary files /dev/null and b/public/icons/font/slate.eot differ
diff --git a/public/icons/font/slate.svg b/public/icons/font/slate.svg
new file mode 100644
index 0000000..1176f69
--- /dev/null
+++ b/public/icons/font/slate.svg
@@ -0,0 +1,29 @@
+
+
+
+Copyright (C) 2013 by original authors @ fontello.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/icons/font/slate.ttf b/public/icons/font/slate.ttf
new file mode 100644
index 0000000..31b3777
Binary files /dev/null and b/public/icons/font/slate.ttf differ
diff --git a/public/icons/font/slate.woff b/public/icons/font/slate.woff
new file mode 100644
index 0000000..a52c7c8
Binary files /dev/null and b/public/icons/font/slate.woff differ
diff --git a/public/images/application.png b/public/images/application.png
new file mode 100644
index 0000000..dc7db91
Binary files /dev/null and b/public/images/application.png differ
diff --git a/public/images/demo.png b/public/images/demo.png
new file mode 100644
index 0000000..2bb41aa
Binary files /dev/null and b/public/images/demo.png differ
diff --git a/public/images/result.png b/public/images/result.png
new file mode 100644
index 0000000..db8a5a8
Binary files /dev/null and b/public/images/result.png differ
diff --git a/public/images/yeoman.png b/public/images/yeoman.png
new file mode 100644
index 0000000..f32abfb
Binary files /dev/null and b/public/images/yeoman.png differ
diff --git a/public/oauth-buttons.css b/public/oauth-buttons.css
new file mode 100644
index 0000000..7ad29b4
--- /dev/null
+++ b/public/oauth-buttons.css
@@ -0,0 +1,30 @@
+.blue-button .oauth a {
+ text-decoration: none;
+ background: #239cbb;
+ box-sizing: border-box;
+ min-height: 35px;
+ width: auto;
+ display: inline-block;
+ padding: 0.9em 1.37em;
+ cursor: pointer;
+ color: #fff !important;
+ font-size: 12px;
+ line-height: 13px;
+ font-weight: 300;
+ text-align: center;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ text-shadow: none;
+ border-radius: 0.2em;
+ border: rgba(0,0,0,0.05) 0.1em solid;
+ -webkit-transition: background 0.3s ease, border-color 0.3s ease;
+ -moz-transition: background 0.3s ease, border-color 0.3s ease;
+ transition: background 0.3s ease, border-color 0.3s ease;
+}
+
+.blue-button .oauth a:hover {
+ background: #01cf9e;
+ color: #fff;
+ text-decoration: none;
+}
+
diff --git a/public/style.css b/public/style.css
new file mode 100644
index 0000000..87aa822
--- /dev/null
+++ b/public/style.css
@@ -0,0 +1,302 @@
+
+* {
+ -webkit-box-sizing: border-box;
+}
+
+body, html {
+ margin: 0;
+ padding: 0;
+ height: 100%;
+}
+
+body {
+ font: 17px/1.5 "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
+ background: white;
+ margin: 0;
+ color: #33333d;
+ overflow-y: scroll;
+ overflow-x: hidden;
+}
+
+a {
+ color: #000;
+}
+
+section {
+ min-height: 50%;
+}
+
+section:not(:last-child) {
+ border-bottom: 1px solid #eee;
+}
+
+section:not(#top) {
+ padding: 150px 100px;
+ text-align: center;
+}
+
+pre {
+ margin: 2em 0;
+ background: white;
+ border-top: 1px solid #eee;
+ border-bottom: 1px solid #eee;
+ padding: 25px;
+ font-size: .9em;
+ font-family: monospace;
+ overflow-x: auto;
+}
+
+xmp {
+ margin: 0;
+}
+
+.content img {
+ width: 100%;
+ border: 1px solid #ddd;
+ padding: 1em;
+ margin: 2em 0;
+ border-radius: 5px;
+}
+
+p {
+ font-weight: 300;
+ font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
+}
+
+code {
+ font-family: monospace;
+ font-size: .9em;
+}
+
+h1 {
+ font-size: 2em;
+ margin-top: 0em;
+ padding-top: 1em;
+}
+
+h1:not(:first-child) {
+ margin-top: 50px;
+}
+
+h2 {
+ margin-top: 80px;
+ font-size: 1.2em;
+}
+
+h3 {
+ margin-top: 40px;
+ font-size: 1em;
+}
+
+ul li {
+ padding: 0.1em 0;
+ /*font-size: .8em;*/
+}
+
+section:nth-child(2n) {
+ background: #fdfdfd;
+ box-shadow: inset 0 1px 0 0 white;
+}
+
+.content {
+ margin: 0 auto;
+ max-width: 750px;
+ text-align: left;
+}
+
+#top {
+ height: 100%;
+}
+
+#heading {
+ -webkit-user-select: none;
+ position: absolute;
+ top: 50%;
+ margin-top: -150px;
+ text-align: center;
+ width: 100%;
+}
+
+#logo {
+ font: 100px 'Italiana', sans-serif;
+ text-transform: lowercase;
+}
+
+#tagline {
+ font-size: 16px;
+}
+
+.github-img {
+ width: 100px;
+}
+
+#menu {
+ position: fixed;
+ top: 35px;
+ right: 30px;
+ z-index: 50;
+}
+
+#menu:hover ul {
+ display: block;
+}
+
+#menu a {
+ color: inherit;
+}
+
+#menu a#toggle {
+ position: absolute;
+ top: 0;
+ right: 0;
+ padding: 5px;
+ background: rgba(255,255,255,.9);
+ border-radius: 2px;
+ border: 1px solid transparent;
+ z-index: 5;
+}
+
+#menu:hover a#toggle {
+ border: 1px solid #efefef;
+ border-bottom: none;
+}
+
+#menu i.icon-menu {
+ font-size: 1.5em;
+}
+
+#menu ul {
+ display: none;
+ position: absolute;
+ width: 200px;
+ top: 2.8em;
+ right: 0;
+ margin: 0;
+ border: 1px solid #efefef;
+ border-bottom: 1px solid #ddd;
+ border-radius: 2px;
+ padding: 25px;
+ background: rgba(255,255,255,.95);
+ box-shadow: 0 1px 3px 0 #eee;
+}
+
+#menu ul li {
+ list-style: none;
+}
+
+#menu ul li a {
+ display: block;
+ text-decoration: none;
+ padding: 3px 0;
+}
+
+#menu ul li a:hover {
+ text-decoration: underline;
+}
+
+ul.task-list {
+ list-style-type: none;
+ padding-left:10px;
+}
+
+ul.task-list .task-list-item-checkbox {
+ margin-right: 10px;
+}
+
+@media screen and (max-width: 700px) {
+ section:not(#top) {
+ padding: 50px 25px;
+ }
+
+ #heading {
+ margin-top: -75px;
+ }
+
+ #logo {
+ font-size: 75px;
+ }
+
+ #tagline {
+ font-size: 12px;
+ }
+}
+
+@media screen and (max-width: 500px) {
+ body {
+ font-size: 13px;
+ }
+}
+
+/* * * * * * * * */
+/* Table Listing */
+/* * * * * * * * */
+
+table {
+ margin: 40px 0;
+ width: 100%;
+}
+
+table tr th {
+ border-bottom: 1px solid #dddddd !important;
+ text-transform: uppercase;
+ font-style: italic;
+}
+
+table tr td,
+table tr th {
+ color: #333;
+ font-weight: 200;
+ line-height: 1.5 !important;
+ border-bottom: 1px solid #eee;
+ padding: 12px 0;
+ vertical-align: top;
+}
+
+table .parameter {
+ width: 35%;
+}
+
+table .smaller-titles .parameter {
+ width: 25%;
+}
+
+table .extra {
+ width: 30% !important;
+}
+
+table .nested {
+ padding-left: 30px !important;
+}
+
+table span.info {
+ display: block;
+ color: #888;
+ font-weight: 200;
+}
+
+table.button .title {
+ text-transform: uppercase;
+ font-weight: 600;
+}
+
+table.button .parameter {
+ width: 100px;
+}
+
+.notice {
+ background-color: #f4f4f4;
+ padding: 1em;
+ border: 1px solid #e4e4e4;
+}
+
+.btn {
+ display: inline-block;
+ text-decoration: none;
+ border: 1px solid #000;
+ padding: 0.5em 1em;
+ margin-right: 0.5em;
+}
+
+.btn-group {
+ margin-top: 2em;
+}
diff --git a/test/runner.html b/test/runner.html
deleted file mode 100644
index f4a00a1..0000000
--- a/test/runner.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- End2end Test Runner
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/spec/directives/oauth.js b/test/spec/directives/oauth.js
deleted file mode 100644
index 0f33f44..0000000
--- a/test/spec/directives/oauth.js
+++ /dev/null
@@ -1,259 +0,0 @@
-'use strict';
-
-describe('oauth', function() {
-
- var $rootScope, $location, $sessionStorage, $httpBackend, $compile, AccessToken, Endpoint, element, scope, result, callback;
-
- var uri = 'http://example.com/oauth/authorize?response_type=token&client_id=client-id&redirect_uri=http://example.com/redirect&scope=scope&state=/';
- var fragment = 'access_token=token&token_type=bearer&expires_in=7200&state=/path';
- var denied = 'error=access_denied&error_description=error';
- var headers = { 'Accept': 'application/json, text/plain, */*', 'Authorization': 'Bearer token' }
- var profile = { id: '1', full_name: 'Alice Wonderland', email: 'alice@example.com' };
-
- beforeEach(module('oauth'));
- beforeEach(module('templates'));
-
- beforeEach(inject(function($injector) { $rootScope = $injector.get('$rootScope') }));
- beforeEach(inject(function($injector) { $compile = $injector.get('$compile') }));
- beforeEach(inject(function($injector) { $location = $injector.get('$location') }));
- beforeEach(inject(function($injector) { $sessionStorage = $injector.get('$sessionStorage') }));
- beforeEach(inject(function($injector) { $httpBackend = $injector.get('$httpBackend') }));
- beforeEach(inject(function($injector) { AccessToken = $injector.get('AccessToken') }));
- beforeEach(inject(function($injector) { Endpoint = $injector.get('Endpoint') }));
- beforeEach(inject(function($injector) { callback = jasmine.createSpy('callback') }));
-
- beforeEach(inject(function($rootScope, $compile) {
- element = angular.element(
- '' +
- 'Sign In ' +
- ' '
- );
- }));
-
- var compile = function() {
- scope = $rootScope;
- $compile(element)(scope);
- scope.$digest();
- }
-
-
- describe('when logged in', function() {
-
- beforeEach(function() {
- $location.hash(fragment);
- });
-
- beforeEach(function() {
- $httpBackend.whenGET('http://example.com/me', headers).respond(profile);
- });
-
- beforeEach(function() {
- $rootScope.$on('oauth:success', callback);
- });
-
- beforeEach(function() {
- compile($rootScope, $compile);
- });
-
- it('shows the link "Logout #{profile.email}"', function() {
- $rootScope.$apply();
- $httpBackend.flush();
- result = element.find('.logged-in').text();
- expect(result).toBe('Logout Alice Wonderland');
- });
-
- it('removes the fragment', function() {
- expect($location.hash()).toBe('');
- });
-
- it('shows the logout link', function() {
- expect(element.find('.logged-out').attr('class')).toMatch('ng-hide');
- expect(element.find('.logged-in').attr('class')).not.toMatch('ng-hide');
- });
-
- it('fires the oauth:login event', function() {
- var event = jasmine.any(Object);
- var token = AccessToken.get();
- expect(callback).toHaveBeenCalledWith(event, token);
- });
-
- describe('when refreshes the page', function() {
-
- beforeEach(function() {
- $rootScope.$on('oauth:success', callback);
- });
-
- beforeEach(function() {
- $location.path('/');
- });
-
- beforeEach(function() {
- compile($rootScope, $compile);
- });
-
- it('keeps being logged in', function() {
- $rootScope.$apply();
- $httpBackend.flush();
- result = element.find('.logged-in').text();
- expect(result).toBe('Logout Alice Wonderland');
- });
-
- it('shows the logout link', function() {
- expect(element.find('.logged-out').attr('class')).toMatch('ng-hide');
- expect(element.find('.logged-in').attr('class')).not.toMatch('ng-hide');
- });
-
- it('fires the oauth:login event', function() {
- var event = jasmine.any(Object);
- var token = AccessToken.get();
- expect(callback).toHaveBeenCalledWith(event, token);
- });
- });
-
-
- describe('when logs out', function() {
-
- beforeEach(function() {
- $rootScope.$on('oauth:logout', callback);
- });
-
- beforeEach(function() {
- element.find('.logged-in').click();
- });
-
- it('shows the login link', function() {
- expect(element.find('.logged-out').attr('class')).not.toMatch('ng-hide');
- expect(element.find('.logged-in').attr('class')).toMatch('ng-hide');
- });
-
- it('fires the oauth:logout event', function() {
- var event = jasmine.any(Object);
- expect(callback).toHaveBeenCalledWith(event);
- });
- });
- });
-
-
- describe('when logged out', function() {
-
- beforeEach(function() {
- $rootScope.$on('oauth:logout', callback);
- });
-
- beforeEach(function() {
- AccessToken.destroy();
- });
-
- beforeEach(function() {
- compile($rootScope, $compile)
- });
-
- beforeEach(function() {
- spyOn(Endpoint, 'redirect');
- });
-
- it('shows the text "Sing In"', function() {
- result = element.find('.logged-out').text();
- expect(result).toBe('Sign In');
- });
-
- it('sets the href attribute', function() {
- result = element.find('.logged-out').click();
- expect(Endpoint.redirect).toHaveBeenCalled();
- });
-
- it('shows the login link', function() {
- expect(element.find('.logged-out').attr('class')).not.toMatch('ng-hide');
- expect(element.find('.logged-in').attr('class')).toMatch('ng-hide');
- });
-
- it('fires the oauth:logout event', function() {
- var event = jasmine.any(Object);
- expect(callback).toHaveBeenCalledWith(event);
- });
- });
-
-
- describe('when denied', function() {
-
- beforeEach(function() {
- $location.hash(denied);
- });
-
- beforeEach(function() {
- $rootScope.$on('oauth:denied', callback);
- });
-
- beforeEach(function() {
- compile($rootScope, $compile)
- });
-
- beforeEach(function() {
- spyOn(Endpoint, 'redirect');
- });
-
- it('shows the text "Denied"', function() {
- result = element.find('.denied').text();
- expect(result).toBe('Access denied. Try again.');
- });
-
- it('sets the href attribute', function() {
- result = element.find('.denied').click();
- expect(Endpoint.redirect).toHaveBeenCalled();
- });
-
- it('shows the login link', function() {
- expect(element.find('.logged-out').attr('class')).toMatch('ng-hide');
- expect(element.find('.logged-in').attr('class')).toMatch('ng-hide');
- expect(element.find('.denied').attr('class')).not.toMatch('ng-hide');
- });
-
- it('fires the oauth:denied event', function() {
- var event = jasmine.any(Object);
- expect(callback).toHaveBeenCalledWith(event);
- });
- });
-
-
- describe('with no custom template', function() {
-
- beforeEach(function() {
- AccessToken.destroy();
- });
-
- beforeEach(function() {
- compile($rootScope, $compile)
- });
-
- it('shows the default template', function() {
- expect(element.find('.btn-oauth').text()).toBe('');
- });
- });
-
-
- describe('with custom template', function() {
-
- beforeEach(function() {
- AccessToken.destroy();
- });
-
- beforeEach(function() {
- compile($rootScope, $compile)
- });
-
- beforeEach(function() {
- $rootScope.$broadcast('oauth:template:update', 'views/templates/button.html');
- $rootScope.$apply();
- });
-
- it('shows the button template', function() {
- expect(element.find('.oauth .logged-out').text()).toBe('Login Button');
- });
- });
-});
diff --git a/test/spec/services/access-token.js b/test/spec/services/access-token.js
deleted file mode 100644
index 508a32d..0000000
--- a/test/spec/services/access-token.js
+++ /dev/null
@@ -1,196 +0,0 @@
-'use strict';
-
-describe('AccessToken', function() {
-
- var result, $location, $sessionStorage, AccessToken, date;
-
- var fragment = 'access_token=token&token_type=bearer&expires_in=7200&state=/path';
- var denied = 'error=access_denied&error_description=error';
- var token = { access_token: 'token', token_type: 'bearer', expires_in: 7200, state: '/path' };
-
- beforeEach(module('oauth'));
-
- beforeEach(inject(function($injector) { $location = $injector.get('$location') }));
- beforeEach(inject(function($injector) { $sessionStorage = $injector.get('$sessionStorage') }));
- beforeEach(inject(function($injector) { AccessToken = $injector.get('AccessToken') }));
-
-
- describe('#set', function() {
-
- describe('when sets the access token', function() {
-
- beforeEach(function() {
- $location.hash(fragment);
- });
-
- beforeEach(function() {
- result = AccessToken.set();
- });
-
- it('sets the access token', function() {
- expect(result.access_token).toEqual('token');
- });
-
- it('sets #expires_at', function() {
- var expected_date = new Date();
- expected_date.setSeconds(expected_date.getSeconds() + 7200 - 60);
- expect(parseInt(result.expires_at/100)).toBe(parseInt(expected_date/100)); // 10 ms
- });
- });
-
- describe('with the access token in the fragment URI', function() {
-
- beforeEach(function() {
- $location.hash(fragment);
- });
-
- beforeEach(function() {
- result = AccessToken.set();
- });
-
- it('sets the access token', function() {
- expect(result.access_token).toEqual('token');
- });
-
- it('removes the fragment string', function() {
- expect($location.hash()).toEqual('');
- });
-
- it('stores the token in the session', function() {
- var stored_token = $sessionStorage.token;
- expect(result.access_token).toEqual('token');
- });
- });
-
- describe('with the access token stored in the session', function() {
-
- beforeEach(function() {
- $sessionStorage.token = token;
- });
-
- beforeEach(function() {
- result = AccessToken.set();
- });
-
- it('sets the access token from session', function() {
- expect(result.access_token).toEqual('token');
- });
- });
-
- describe('with the denied message in the fragment URI', function() {
-
- beforeEach(function() {
- $location.hash(denied);
- });
-
- beforeEach(function() {
- result = AccessToken.set();
- });
-
- it('sets the access token', function() {
- expect(result.error).toEqual('access_denied');
- });
-
- it('removes the fragment string', function() {
- expect($location.hash()).toEqual('');
- });
-
- it('stores the error message in the session', function() {
- var stored_token = $sessionStorage.token;
- expect(result.error).toBe('access_denied');
- });
- });
- });
-
-
- describe('#get', function() {
-
- beforeEach(function() {
- $location.hash(fragment);
- });
-
- beforeEach(function() {
- AccessToken.set();
- });
-
- beforeEach(function() {
- result = AccessToken.get();
- });
-
- it('sets the access token', function() {
- expect(result.access_token).toEqual('token');
- });
- });
-
-
- describe('#destroy', function() {
-
- beforeEach(function() {
- $location.hash(fragment);
- });
-
- beforeEach(function() {
- AccessToken.set();
- });
-
- beforeEach(function() {
- result = AccessToken.destroy();
- });
-
- it('sets the access token', function() {
- expect(result).toBeNull();
- });
-
- it('reset the cache', function() {
- expect($sessionStorage.token).toBeUndefined;
- });
- });
-
-
- describe('#expired', function() {
-
- beforeEach(function() {
- $location.hash(fragment);
- });
-
- beforeEach(function() {
- AccessToken.set();
- });
-
- describe('when not expired', function() {
-
- beforeEach(function() {
- result = AccessToken.expired();
- });
-
- it('returns false', function() {
- expect(result).toBe(false);
- });
- });
-
- describe('when expired', function() {
-
- beforeEach(function() {
- date = new Date();
- date.setTime(date.getTime() + 86400000);
- });
-
- beforeEach(function() {
- Timecop.install();
- Timecop.travel(date); // go to the future for one day
- });
-
- beforeEach(function() {
- result = AccessToken.expired();
- });
-
- afterEach(function() {
- Timecop.uninstall();
- });
-
- it('returns true', function() {
- expect(result).toBe(true);
- });
- });
- });
-});
diff --git a/test/spec/services/endpoint.js b/test/spec/services/endpoint.js
deleted file mode 100644
index 352b4a8..0000000
--- a/test/spec/services/endpoint.js
+++ /dev/null
@@ -1,59 +0,0 @@
-'use strict';
-
-describe('Endpoint', function() {
-
- var result, $location, $sessionStorage, Endpoint;
-
- var fragment = 'access_token=token&token_type=bearer&expires_in=7200&state=/path';
- var params = { site: 'http://example.com/', clientId: 'client-id', redirectUri: 'http://example.com/redirect', scope: 'scope', authorizePath: '/oauth/authorize' };
- var uri = 'http://example.com/oauth/authorize?response_type=token&client_id=client-id&redirect_uri=http://example.com/redirect&scope=scope&state=/';
-
- beforeEach(module('oauth'));
-
- beforeEach(inject(function($injector) { $location = $injector.get('$location') }));
- beforeEach(inject(function($injector) { $sessionStorage = $injector.get('$sessionStorage') }));
- beforeEach(inject(function($injector) { Endpoint = $injector.get('Endpoint') }));
-
-
- describe('#set', function() {
-
- beforeEach(function() {
- result = Endpoint.set(params);
- });
-
- it('returns the oauth server endpoint', function() {
- expect(result).toEqual(uri);
- });
-
- describe('when in a specific /path', function() {
-
- beforeEach(function() {
- $location.path('/path');
- });
-
- beforeEach(function() {
- result = Endpoint.set(params);
- });
-
- it('returns previous path in status', function() {
- expect(result).toEqual(uri + 'path');
- });
- });
- });
-
-
- describe('#get', function() {
-
- beforeEach(function() {
- Endpoint.set(params);
- });
-
- beforeEach(function() {
- result = Endpoint.get();
- });
-
- it('returns the oauth server endpoint', function() {
- expect(result).toEqual(uri);
- });
- });
-});
diff --git a/test/spec/services/profile.js b/test/spec/services/profile.js
deleted file mode 100644
index 3a5e330..0000000
--- a/test/spec/services/profile.js
+++ /dev/null
@@ -1,85 +0,0 @@
-'use strict';
-
-describe('Profile', function() {
-
- var $rootScope, $location, $httpBackend, $http, AccessToken, result, date, callback;
-
- var fragment = 'access_token=token&token_type=bearer&expires_in=7200&state=/path';
- var headers = { 'Accept': 'application/json, text/plain, */*', 'Authorization': 'Bearer token' }
- var params = { site: 'http://example.com/', client: 'client-id', redirect: 'http://example.com/redirect', scope: 'scope', profileUri: 'http://example.com/me' };
- var resource = { id: '1', name: 'Alice' };
-
- beforeEach(module('oauth'));
-
- beforeEach(inject(function($injector) { $rootScope = $injector.get('$rootScope') }));
- beforeEach(inject(function($injector) { $location = $injector.get('$location') }));
- beforeEach(inject(function($injector) { $httpBackend = $injector.get('$httpBackend') }));
- beforeEach(inject(function($injector) { $http = $injector.get('$http') }));
- beforeEach(inject(function($injector) { AccessToken = $injector.get('AccessToken') }));
-
- beforeEach(function() { callback = jasmine.createSpy('callback') });
-
-
- describe('.get', function() {
-
- describe('when authenticated', function() {
-
- beforeEach(function() {
- $location.hash(fragment);
- AccessToken.set(params);
- });
-
- beforeEach(function() {
- $httpBackend.whenGET('http://example.com/me', headers).respond(resource);
- });
-
- it('makes the request', inject(function(Profile) {
- $httpBackend.expect('GET', 'http://example.com/me');
- Profile.get(params.profileUri);
- $rootScope.$apply();
- $httpBackend.flush();
- }));
-
- it('gets the resource', inject(function(Profile) {
- Profile.get(params.profileUri).success(function(response) { result = response });
- $rootScope.$apply();
- $httpBackend.flush();
- expect(result.name).toEqual('Alice');
- }));
-
-
- describe('when expired', function() {
-
- beforeEach(function() {
- $rootScope.$on('oauth:expired', callback);
- });
-
- beforeEach(function() {
- date = new Date();
- date.setTime(date.getTime() + 86400000);
- });
-
- beforeEach(function() {
- Timecop.install();
- Timecop.travel(date); // go one day in the future
- });
-
- beforeEach(function() {
- })
-
- afterEach(function() {
- Timecop.uninstall();
- });
-
- it('fires the oauth:expired event', inject(function(Profile) {
- Profile.get(params.profileUri);
- $rootScope.$apply();
- $httpBackend.flush();
- var event = jasmine.any(Object);
- var token = jasmine.any(Object);
- expect(callback).toHaveBeenCalledWith(event, token);
- }));
- });
- });
- });
-});