diff --git a/.gitignore b/.gitignore index 924d1e3ac..328b13d38 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,9 @@ coverage/ *.swp *.sh + +config.yml + +npm-debug.log + +notifications/ diff --git a/.travis.yml b/.travis.yml index 84b9c1b98..4e150744b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,13 +4,17 @@ node_js: services: - docker - ntp +addons: + apt: + packages: + - libgif-dev before_install: npm install -g npm@'>=2.13.5' script: - npm test - docker-compose build - docker-compose up -d - sleep 5 -- npm run-script integration-test +- ./scripts/check_services.sh deploy: provider: npm email: clement.michaud34@gmail.com diff --git a/Dockerfile b/Dockerfile index 00fcfc7f0..1bf24d1da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,4 +10,7 @@ COPY src /usr/src ENV PORT=80 EXPOSE 80 -CMD ["node", "index.js"] +VOLUME /etc/auth-server +VOLUME /var/lib/auth-server + +CMD ["node", "index.js", "/etc/auth-server/config.yml"] diff --git a/config.template.yml b/config.template.yml new file mode 100644 index 000000000..d514ba316 --- /dev/null +++ b/config.template.yml @@ -0,0 +1,33 @@ + +### Level of verbosity for logs +logs_level: info + +### Configuration of your LDAP +ldap: + url: ldap://ldap + base_dn: ou=users,dc=example,dc=com + user: cn=admin,dc=example,dc=com + password: password + +### Configuration of session cookies +session: + secret: unsecure_secret + expiration: 3600000 + +### The directory where the DB files will be saved +store_directory: /var/lib/auth-server/store + + +### Notifications are sent to users when they require a password reset, a u2f +### registration or a TOTP registration. +### Use only one available configuration: filesystem, gmail +notifier: + ### For testing purpose, notifications can be sent in a file + filesystem: + filename: /var/lib/auth-server/notifications/notification.txt + + ### Use your gmail account to send the notifications. You can use an app password. + # gmail: + # username: user@example.com + # password: yourpassword + diff --git a/doc/api_data.js b/doc/api_data.js new file mode 100644 index 000000000..3591eab6f --- /dev/null +++ b/doc/api_data.js @@ -0,0 +1,1031 @@ +define({ "api": [ + { + "type": "post", + "url": "/authentication/2ndfactor/u2f/sign", + "title": "U2F Complete authentication", + "name": "CompleteU2FAuthentication", + "group": "Authentication", + "version": "1.0.0", + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "
The U2F authentication succeeded.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "type": "none", + "optional": false, + "field": "error", + "description": "No authentication request has been provided.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Complete authentication request of the U2F device.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Authentication", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "get", + "url": "/authentication/2ndfactor/u2f/sign_request", + "title": "U2F Start authentication", + "name": "StartU2FAuthentication", + "group": "Authentication", + "version": "1.0.0", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "optional": false, + "field": "authentication_request", + "description": "The U2F authentication request.
" + } + ] + } + }, + "error": { + "fields": { + "Error 401": [ + { + "group": "Error 401", + "type": "none", + "optional": false, + "field": "error", + "description": "There is no key registered for user in session.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Initiate an authentication request using a U2F device.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Authentication", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/1stfactor", + "title": "LDAP authentication", + "name": "ValidateFirstFactor", + "group": "Authentication", + "version": "1.0.0", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "username", + "description": "User username.
" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "password", + "description": "User password.
" + } + ] + } + }, + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "1st factor is validated.
" + } + ] + } + }, + "error": { + "fields": { + "Error 401": [ + { + "group": "Error 401", + "type": "none", + "optional": false, + "field": "error", + "description": "1st factor is not validated.
" + } + ], + "Error 403": [ + { + "group": "Error 403", + "type": "none", + "optional": false, + "field": "error", + "description": "Access has been restricted after too many authentication attempts
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Verify credentials against the LDAP.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Authentication", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/2ndfactor/totp", + "title": "TOTP authentication", + "name": "ValidateTOTPSecondFactor", + "group": "Authentication", + "version": "1.0.0", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "token", + "description": "TOTP token.
" + } + ] + } + }, + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "TOTP token is valid.
" + } + ] + } + }, + "error": { + "fields": { + "Error 401": [ + { + "group": "Error 401", + "type": "none", + "optional": false, + "field": "error", + "description": "TOTP token is invalid.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Verify TOTP token. The user is authenticated upon success.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Authentication", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "get", + "url": "/authentication/login", + "title": "Serve login page", + "name": "Login", + "group": "Pages", + "version": "1.0.0", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "redirect", + "description": "Redirect to this URL when user is authenticated.
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "Content", + "description": "The content of the login page.
" + } + ] + } + }, + "description": "Create a user session and serve the login page along with a cookie.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Pages" + }, + { + "type": "get", + "url": "/authentication/logout", + "title": "Server logout page", + "name": "Logout", + "group": "Pages", + "version": "1.0.0", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "redirect", + "description": "Redirect to this URL when user is deauthenticated.
" + } + ] + } + }, + "success": { + "fields": { + "Success 301": [ + { + "group": "Success 301", + "optional": false, + "field": "redirect", + "description": "Redirect to the URL.
" + } + ] + } + }, + "description": "Deauthenticate the user and redirect him.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Pages" + }, + { + "type": "get", + "url": "/authentication/reset-password", + "title": "Serve password reset form.", + "name": "ServePasswordResetForm", + "group": "Pages", + "version": "1.0.0", + "description": "Serves password reset form that allow the user to provide the new password.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Pages", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "identity_token", + "description": "The one-time identity validation token provided in the email.
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "content", + "description": "The content of the page.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + } + }, + { + "type": "get", + "url": "/authentication/u2f-register", + "title": "Serve U2F registration page", + "name": "ServeU2FRegistrationPage", + "group": "Pages", + "version": "1.0.0", + "description": "Serves the U2F registration page that asks the user to touch the token of the U2F device.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Pages", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "identity_token", + "description": "The one-time identity validation token provided in the email.
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "content", + "description": "The content of the page.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/2ndfactor/u2f/register", + "title": "U2F Complete device registration", + "name": "CompleteU2FRegistration", + "group": "Registration", + "version": "1.0.0", + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "The U2F registration succeeded.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "type": "none", + "optional": false, + "field": "error", + "description": "Unexpected identity validation challenge.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Complete U2F registration request.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/new-totp-secret", + "title": "Generate TOTP secret", + "name": "GenerateTOTPSecret", + "group": "Registration", + "version": "1.0.0", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "base32", + "description": "The base32 representation of the secret.
" + }, + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "ascii", + "description": "The ASCII representation of the secret.
" + }, + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "qrcode", + "description": "The QRCode of the secret in URI format.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "type": "String", + "optional": false, + "field": "error", + "description": "No user provided in the session or unexpected identity validation challenge in the session.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message
" + } + ] + } + }, + "description": "Generate a new TOTP secret and returns it.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/reset-password", + "title": "Request for password reset", + "name": "RequestPasswordReset", + "group": "Registration", + "version": "1.0.0", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "Identity validation has been initiated.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 400": [ + { + "group": "Error 400", + "optional": false, + "field": "InvalidIdentity", + "description": "User identity is invalid.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "This request issue an identity validation token for the user bound to the session. It sends a challenge to the email address set in the user LDAP entry. The user must visit the sent URL to complete the validation and continue the registration process.
" + }, + { + "type": "post", + "url": "/authentication/totp-register", + "title": "Request TOTP registration", + "name": "RequestTOTPRegistration", + "group": "Registration", + "version": "1.0.0", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "Identity validation has been initiated.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 400": [ + { + "group": "Error 400", + "optional": false, + "field": "InvalidIdentity", + "description": "User identity is invalid.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "This request issue an identity validation token for the user bound to the session. It sends a challenge to the email address set in the user LDAP entry. The user must visit the sent URL to complete the validation and continue the registration process.
" + }, + { + "type": "post", + "url": "/authentication/u2f-register", + "title": "Request U2F registration", + "name": "RequestU2FRegistration", + "group": "Registration", + "version": "1.0.0", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "Identity validation has been initiated.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 400": [ + { + "group": "Error 400", + "optional": false, + "field": "InvalidIdentity", + "description": "User identity is invalid.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "This request issue an identity validation token for the user bound to the session. It sends a challenge to the email address set in the user LDAP entry. The user must visit the sent URL to complete the validation and continue the registration process.
" + }, + { + "type": "get", + "url": "/authentication/totp-register", + "title": "Serve TOTP registration page", + "name": "ServeTOTPRegistrationPage", + "group": "Registration", + "version": "1.0.0", + "description": "Serves the TOTP registration page that displays the secret. The secret is a QRCode and a base32 secret.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "identity_token", + "description": "The one-time identity validation token provided in the email.
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "content", + "description": "The content of the page.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/new-password", + "title": "Set LDAP password", + "name": "SetLDAPPassword", + "group": "Registration", + "version": "1.0.0", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "password", + "description": "New password
" + } + ] + } + }, + "description": "Set a new password for the user.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "get", + "url": "/authentication/2ndfactor/u2f/register_request", + "title": "U2F Start device registration", + "name": "StartU2FRegistration", + "group": "Registration", + "version": "1.0.0", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "optional": false, + "field": "authentication_request", + "description": "The U2F registration request.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "type": "none", + "optional": false, + "field": "error", + "description": "Unexpected identity validation challenge.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Initiate a U2F device registration request.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "get", + "url": "/authentication/verify", + "title": "Verify user authentication", + "name": "VerifyAuthentication", + "group": "Verification", + "version": "1.0.0", + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "The user is authenticated.
" + } + ] + } + }, + "error": { + "fields": { + "Error 401": [ + { + "group": "Error 401", + "optional": false, + "field": "status", + "description": "The user is not authenticated.
" + } + ] + } + }, + "description": "Verify that the user is authenticated, i.e., the two factors have been validated
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Verification", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + } +] }); diff --git a/doc/api_data.json b/doc/api_data.json new file mode 100644 index 000000000..60247d1f4 --- /dev/null +++ b/doc/api_data.json @@ -0,0 +1,1031 @@ +[ + { + "type": "post", + "url": "/authentication/2ndfactor/u2f/sign", + "title": "U2F Complete authentication", + "name": "CompleteU2FAuthentication", + "group": "Authentication", + "version": "1.0.0", + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "The U2F authentication succeeded.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "type": "none", + "optional": false, + "field": "error", + "description": "No authentication request has been provided.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Complete authentication request of the U2F device.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Authentication", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "get", + "url": "/authentication/2ndfactor/u2f/sign_request", + "title": "U2F Start authentication", + "name": "StartU2FAuthentication", + "group": "Authentication", + "version": "1.0.0", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "optional": false, + "field": "authentication_request", + "description": "The U2F authentication request.
" + } + ] + } + }, + "error": { + "fields": { + "Error 401": [ + { + "group": "Error 401", + "type": "none", + "optional": false, + "field": "error", + "description": "There is no key registered for user in session.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Initiate an authentication request using a U2F device.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Authentication", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/1stfactor", + "title": "LDAP authentication", + "name": "ValidateFirstFactor", + "group": "Authentication", + "version": "1.0.0", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "username", + "description": "User username.
" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "password", + "description": "User password.
" + } + ] + } + }, + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "1st factor is validated.
" + } + ] + } + }, + "error": { + "fields": { + "Error 401": [ + { + "group": "Error 401", + "type": "none", + "optional": false, + "field": "error", + "description": "1st factor is not validated.
" + } + ], + "Error 403": [ + { + "group": "Error 403", + "type": "none", + "optional": false, + "field": "error", + "description": "Access has been restricted after too many authentication attempts
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Verify credentials against the LDAP.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Authentication", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/2ndfactor/totp", + "title": "TOTP authentication", + "name": "ValidateTOTPSecondFactor", + "group": "Authentication", + "version": "1.0.0", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "token", + "description": "TOTP token.
" + } + ] + } + }, + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "TOTP token is valid.
" + } + ] + } + }, + "error": { + "fields": { + "Error 401": [ + { + "group": "Error 401", + "type": "none", + "optional": false, + "field": "error", + "description": "TOTP token is invalid.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Verify TOTP token. The user is authenticated upon success.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Authentication", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "get", + "url": "/authentication/login", + "title": "Serve login page", + "name": "Login", + "group": "Pages", + "version": "1.0.0", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "redirect", + "description": "Redirect to this URL when user is authenticated.
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "Content", + "description": "The content of the login page.
" + } + ] + } + }, + "description": "Create a user session and serve the login page along with a cookie.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Pages" + }, + { + "type": "get", + "url": "/authentication/logout", + "title": "Server logout page", + "name": "Logout", + "group": "Pages", + "version": "1.0.0", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "redirect", + "description": "Redirect to this URL when user is deauthenticated.
" + } + ] + } + }, + "success": { + "fields": { + "Success 301": [ + { + "group": "Success 301", + "optional": false, + "field": "redirect", + "description": "Redirect to the URL.
" + } + ] + } + }, + "description": "Deauthenticate the user and redirect him.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Pages" + }, + { + "type": "get", + "url": "/authentication/reset-password", + "title": "Serve password reset form.", + "name": "ServePasswordResetForm", + "group": "Pages", + "version": "1.0.0", + "description": "Serves password reset form that allow the user to provide the new password.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Pages", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "identity_token", + "description": "The one-time identity validation token provided in the email.
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "content", + "description": "The content of the page.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + } + }, + { + "type": "get", + "url": "/authentication/u2f-register", + "title": "Serve U2F registration page", + "name": "ServeU2FRegistrationPage", + "group": "Pages", + "version": "1.0.0", + "description": "Serves the U2F registration page that asks the user to touch the token of the U2F device.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Pages", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "identity_token", + "description": "The one-time identity validation token provided in the email.
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "content", + "description": "The content of the page.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/2ndfactor/u2f/register", + "title": "U2F Complete device registration", + "name": "CompleteU2FRegistration", + "group": "Registration", + "version": "1.0.0", + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "The U2F registration succeeded.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "type": "none", + "optional": false, + "field": "error", + "description": "Unexpected identity validation challenge.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Complete U2F registration request.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/new-totp-secret", + "title": "Generate TOTP secret", + "name": "GenerateTOTPSecret", + "group": "Registration", + "version": "1.0.0", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "base32", + "description": "The base32 representation of the secret.
" + }, + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "ascii", + "description": "The ASCII representation of the secret.
" + }, + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "qrcode", + "description": "The QRCode of the secret in URI format.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "type": "String", + "optional": false, + "field": "error", + "description": "No user provided in the session or unexpected identity validation challenge in the session.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message
" + } + ] + } + }, + "description": "Generate a new TOTP secret and returns it.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/reset-password", + "title": "Request for password reset", + "name": "RequestPasswordReset", + "group": "Registration", + "version": "1.0.0", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "Identity validation has been initiated.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 400": [ + { + "group": "Error 400", + "optional": false, + "field": "InvalidIdentity", + "description": "User identity is invalid.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "This request issue an identity validation token for the user bound to the session. It sends a challenge to the email address set in the user LDAP entry. The user must visit the sent URL to complete the validation and continue the registration process.
" + }, + { + "type": "post", + "url": "/authentication/totp-register", + "title": "Request TOTP registration", + "name": "RequestTOTPRegistration", + "group": "Registration", + "version": "1.0.0", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "Identity validation has been initiated.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 400": [ + { + "group": "Error 400", + "optional": false, + "field": "InvalidIdentity", + "description": "User identity is invalid.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "This request issue an identity validation token for the user bound to the session. It sends a challenge to the email address set in the user LDAP entry. The user must visit the sent URL to complete the validation and continue the registration process.
" + }, + { + "type": "post", + "url": "/authentication/u2f-register", + "title": "Request U2F registration", + "name": "RequestU2FRegistration", + "group": "Registration", + "version": "1.0.0", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "Identity validation has been initiated.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 400": [ + { + "group": "Error 400", + "optional": false, + "field": "InvalidIdentity", + "description": "User identity is invalid.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "This request issue an identity validation token for the user bound to the session. It sends a challenge to the email address set in the user LDAP entry. The user must visit the sent URL to complete the validation and continue the registration process.
" + }, + { + "type": "get", + "url": "/authentication/totp-register", + "title": "Serve TOTP registration page", + "name": "ServeTOTPRegistrationPage", + "group": "Registration", + "version": "1.0.0", + "description": "Serves the TOTP registration page that displays the secret. The secret is a QRCode and a base32 secret.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + }, + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "identity_token", + "description": "The one-time identity validation token provided in the email.
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "content", + "description": "The content of the page.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "optional": false, + "field": "AccessDenied", + "description": "Access is denied.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + } + }, + { + "type": "post", + "url": "/authentication/new-password", + "title": "Set LDAP password", + "name": "SetLDAPPassword", + "group": "Registration", + "version": "1.0.0", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "password", + "description": "New password
" + } + ] + } + }, + "description": "Set a new password for the user.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "get", + "url": "/authentication/2ndfactor/u2f/register_request", + "title": "U2F Start device registration", + "name": "StartU2FRegistration", + "group": "Registration", + "version": "1.0.0", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "optional": false, + "field": "authentication_request", + "description": "The U2F registration request.
" + } + ] + } + }, + "error": { + "fields": { + "Error 403": [ + { + "group": "Error 403", + "type": "none", + "optional": false, + "field": "error", + "description": "Unexpected identity validation challenge.
" + } + ], + "Error 500": [ + { + "group": "Error 500", + "type": "String", + "optional": false, + "field": "error", + "description": "Internal error message.
" + } + ] + } + }, + "description": "Initiate a U2F device registration request.
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Registration", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + }, + { + "type": "get", + "url": "/authentication/verify", + "title": "Verify user authentication", + "name": "VerifyAuthentication", + "group": "Verification", + "version": "1.0.0", + "success": { + "fields": { + "Success 204": [ + { + "group": "Success 204", + "optional": false, + "field": "status", + "description": "The user is authenticated.
" + } + ] + } + }, + "error": { + "fields": { + "Error 401": [ + { + "group": "Error 401", + "optional": false, + "field": "status", + "description": "The user is not authenticated.
" + } + ] + } + }, + "description": "Verify that the user is authenticated, i.e., the two factors have been validated
", + "filename": "src/lib/setup_endpoints.js", + "groupTitle": "Verification", + "header": { + "fields": { + "Header": [ + { + "group": "Header", + "type": "String", + "optional": false, + "field": "Cookie", + "description": "Cookie containing 'connect.sid', the user session token.
" + } + ] + } + } + } +] diff --git a/doc/api_project.js b/doc/api_project.js new file mode 100644 index 000000000..e51a09d65 --- /dev/null +++ b/doc/api_project.js @@ -0,0 +1,15 @@ +define({ + "title": "Authelia API documentation", + "name": "authelia", + "version": "1.0.11", + "description": "2-factor authentication server using LDAP as 1st factor and TOTP or U2F as 2nd factor", + "sampleUrl": false, + "defaultVersion": "0.0.0", + "apidoc": "0.3.0", + "generator": { + "name": "apidoc", + "time": "2017-01-29T00:44:17.687Z", + "url": "http://apidocjs.com", + "version": "0.17.5" + } +}); diff --git a/doc/api_project.json b/doc/api_project.json new file mode 100644 index 000000000..8962ef15d --- /dev/null +++ b/doc/api_project.json @@ -0,0 +1,15 @@ +{ + "title": "Authelia API documentation", + "name": "authelia", + "version": "1.0.11", + "description": "2-factor authentication server using LDAP as 1st factor and TOTP or U2F as 2nd factor", + "sampleUrl": false, + "defaultVersion": "0.0.0", + "apidoc": "0.3.0", + "generator": { + "name": "apidoc", + "time": "2017-01-29T00:44:17.687Z", + "url": "http://apidocjs.com", + "version": "0.17.5" + } +} diff --git a/doc/css/style.css b/doc/css/style.css new file mode 100644 index 000000000..eb953166b --- /dev/null +++ b/doc/css/style.css @@ -0,0 +1,568 @@ +/* ------------------------------------------------------------------------------------------ + * Content + * ------------------------------------------------------------------------------------------ */ +body { + min-width: 980px; + max-width: 1280px; +} + +body, p, a, div, th, td { + font-family: "Source Sans Pro", sans-serif; + font-weight: 400; + font-size: 16px; +} + +td.code { + font-size: 14px; + font-family: "Source Code Pro", monospace; + font-style: normal; + font-weight: 400; +} + +#content { + padding-top: 16px; + z-Index: -1; + margin-left: 270px; +} + +p { + color: #808080; +} + +h1 { + font-family: "Source Sans Pro Semibold", sans-serif; + font-weight: normal; + font-size: 44px; + line-height: 50px; + margin: 0 0 10px 0; + padding: 0; +} + +h2 { + font-family: "Source Sans Pro", sans-serif; + font-weight: normal; + font-size: 24px; + line-height: 40px; + margin: 0 0 20px 0; + padding: 0; +} + +section { + border-top: 1px solid #ebebeb; + padding: 30px 0; +} + +section h1 { + font-family: "Source Sans Pro", sans-serif; + font-weight: 700; + font-size: 32px; + line-height: 40px; + padding-bottom: 14px; + margin: 0 0 20px 0; + padding: 0; +} + +article { + padding: 14px 0 30px 0; +} + +article h1 { + font-family: "Source Sans Pro Bold", sans-serif; + font-weight: 600; + font-size: 24px; + line-height: 26px; +} + +article h2 { + font-family: "Source Sans Pro", sans-serif; + font-weight: 600; + font-size: 18px; + line-height: 24px; + margin: 0 0 10px 0; +} + +article h3 { + font-family: "Source Sans Pro", sans-serif; + font-weight: 600; + font-size: 16px; + line-height: 18px; + margin: 0 0 10px 0; +} + +article h4 { + font-family: "Source Sans Pro", sans-serif; + font-weight: 600; + font-size: 14px; + line-height: 16px; + margin: 0 0 8px 0; +} + +table { + border-collapse: collapse; + width: 100%; + margin: 0 0 20px 0; +} + +th { + background-color: #f5f5f5; + text-align: left; + font-family: "Source Sans Pro", sans-serif; + font-weight: 700; + padding: 4px 8px; + border: #e0e0e0 1px solid; +} + +td { + vertical-align: top; + padding: 10px 8px 0 8px; + border: #e0e0e0 1px solid; +} + +#generator .content { + color: #b0b0b0; + border-top: 1px solid #ebebeb; + padding: 10px 0; +} + +.label-optional { + float: right; + background-color: grey; + margin-top: 4px; +} + +.open-left { + right: 0; + left: auto; +} + +/* ------------------------------------------------------------------------------------------ + * apidoc - intro + * ------------------------------------------------------------------------------------------ */ + +#apidoc .apidoc { + border-top: 1px solid #ebebeb; + padding: 30px 0; +} + +#apidoc h1 { + font-family: "Source Sans Pro", sans-serif; + font-weight: 700; + font-size: 32px; + line-height: 40px; + padding-bottom: 14px; + margin: 0 0 20px 0; + padding: 0; +} + +#apidoc h2 { + font-family: "Source Sans Pro Bold", sans-serif; + font-weight: 600; + font-size: 22px; + line-height: 26px; + padding-top: 14px; +} + +/* ------------------------------------------------------------------------------------------ + * pre / code + * ------------------------------------------------------------------------------------------ */ +pre { + background-color: #292b36; + color: #ffffff; + padding: 10px; + border-radius: 6px; + position: relative; + margin: 10px 0 20px 0; +} + +pre.prettyprint { + width: 100%; +} + +code.language-text { + word-wrap: break-word; +} + +pre.language-json { + overflow: auto; +} + +pre.language-html { + margin: 0 0 20px 0; +} + +.type { + font-family: "Source Sans Pro", sans-serif; + font-weight: 600; + font-size: 15px; + display: inline-block; + margin: 0 0 5px 0; + padding: 4px 5px; + border-radius: 6px; + text-transform: uppercase; + background-color: #3387CC; + color: #ffffff; +} + +.type__get { + background-color: green; +} + +.type__put { + background-color: #e5c500; +} + +.type__post { + background-color: #4070ec; +} + +.type__delete { + background-color: #ed0039; +} + +pre.language-api .str { + color: #ffffff; +} + +pre.language-api .pln, +pre.language-api .pun { + color: #65B042; +} + +pre code { + display: block; + font-size: 14px; + font-family: "Source Code Pro", monospace; + font-style: normal; + font-weight: 400; + word-wrap: normal; + white-space: pre; +} + +pre code.sample-request-response-json { + white-space: pre-wrap; + max-height: 500px; + overflow: auto; +} + +/* ------------------------------------------------------------------------------------------ + * Sidenav + * ------------------------------------------------------------------------------------------ */ +.sidenav { + width: 228px; + margin: 0; + padding: 0 20px 20px 20px; + position: fixed; + top: 50px; + left: 0; + bottom: 0; + overflow-x: hidden; + overflow-y: auto; + background-color: #f5f5f5; + z-index: 10; +} + +.sidenav > li > a { + display: block; + width: 192px; + margin: 0; + padding: 2px 11px; + border: 0; + border-left: transparent 4px solid; + border-right: transparent 4px solid; + font-family: "Source Sans Pro", sans-serif; + font-weight: 400; + font-size: 14px; +} + +.sidenav > li.nav-header { + margin-top: 8px; + margin-bottom: 8px; +} + +.sidenav > li.nav-header > a { + padding: 5px 15px; + border: 1px solid #e5e5e5; + width: 190px; + font-family: "Source Sans Pro", sans-serif; + font-weight: 700; + font-size: 16px; + background-color: #ffffff; +} + +.sidenav > li.active > a { + position: relative; + z-index: 2; + background-color: #0088cc; + color: #ffffff; +} + +.sidenav > li.has-modifications a { + border-right: #60d060 4px solid; +} + +.sidenav > li.is-new a { + border-left: #e5e5e5 4px solid; +} + +/* ------------------------------------------------------------------------------------------ + * Side nav search + * ------------------------------------------------------------------------------------------ */ +.sidenav-search { + width: 228px; + left: 0px; + position: fixed; + padding: 16px 20px 10px 20px; + background-color: #F5F5F5; + z-index: 11; +} + +.sidenav-search .search { + height: 26px; +} + +.search-reset { + position: absolute; + display: block; + cursor: pointer; + width: 20px; + height: 20px; + text-align: center; + right: 28px; + top: 17px; + background-color: #fff; +} + +/* ------------------------------------------------------------------------------------------ + * Compare + * ------------------------------------------------------------------------------------------ */ + +ins { + background: #60d060; + text-decoration: none; + color: #000000; +} + +del { + background: #f05050; + color: #000000; +} + +.label-ins { + background-color: #60d060; +} + +.label-del { + background-color: #f05050; + text-decoration: line-through; +} + +pre.ins { + background-color: #60d060; +} + +pre.del { + background-color: #f05050; + text-decoration: line-through; +} + +table.ins th, +table.ins td { + background-color: #60d060; +} + +table.del th, +table.del td { + background-color: #f05050; + text-decoration: line-through; +} + +tr.ins td { + background-color: #60d060; +} + +tr.del td { + background-color: #f05050; + text-decoration: line-through; +} + +/* ------------------------------------------------------------------------------------------ + * Spinner + * ------------------------------------------------------------------------------------------ */ + +#loader { + position: absolute; + width: 100%; +} + +#loader p { + padding-top: 80px; + margin-left: -4px; +} + +.spinner { + margin: 200px auto; + width: 60px; + height: 60px; + position: relative; +} + +.container1 > div, .container2 > div, .container3 > div { + width: 14px; + height: 14px; + background-color: #0088cc; + + border-radius: 100%; + position: absolute; + -webkit-animation: bouncedelay 1.2s infinite ease-in-out; + animation: bouncedelay 1.2s infinite ease-in-out; + /* Prevent first frame from flickering when animation starts */ + -webkit-animation-fill-mode: both; + animation-fill-mode: both; +} + +.spinner .spinner-container { + position: absolute; + width: 100%; + height: 100%; +} + +.container2 { + -webkit-transform: rotateZ(45deg); + transform: rotateZ(45deg); +} + +.container3 { + -webkit-transform: rotateZ(90deg); + transform: rotateZ(90deg); +} + +.circle1 { top: 0; left: 0; } +.circle2 { top: 0; right: 0; } +.circle3 { right: 0; bottom: 0; } +.circle4 { left: 0; bottom: 0; } + +.container2 .circle1 { + -webkit-animation-delay: -1.1s; + animation-delay: -1.1s; +} + +.container3 .circle1 { + -webkit-animation-delay: -1.0s; + animation-delay: -1.0s; +} + +.container1 .circle2 { + -webkit-animation-delay: -0.9s; + animation-delay: -0.9s; +} + +.container2 .circle2 { + -webkit-animation-delay: -0.8s; + animation-delay: -0.8s; +} + +.container3 .circle2 { + -webkit-animation-delay: -0.7s; + animation-delay: -0.7s; +} + +.container1 .circle3 { + -webkit-animation-delay: -0.6s; + animation-delay: -0.6s; +} + +.container2 .circle3 { + -webkit-animation-delay: -0.5s; + animation-delay: -0.5s; +} + +.container3 .circle3 { + -webkit-animation-delay: -0.4s; + animation-delay: -0.4s; +} + +.container1 .circle4 { + -webkit-animation-delay: -0.3s; + animation-delay: -0.3s; +} + +.container2 .circle4 { + -webkit-animation-delay: -0.2s; + animation-delay: -0.2s; +} + +.container3 .circle4 { + -webkit-animation-delay: -0.1s; + animation-delay: -0.1s; +} + +@-webkit-keyframes bouncedelay { + 0%, 80%, 100% { -webkit-transform: scale(0.0) } + 40% { -webkit-transform: scale(1.0) } +} + +@keyframes bouncedelay { + 0%, 80%, 100% { + transform: scale(0.0); + -webkit-transform: scale(0.0); + } 40% { + transform: scale(1.0); + -webkit-transform: scale(1.0); + } +} + +/* ------------------------------------------------------------------------------------------ + * Tabs + * ------------------------------------------------------------------------------------------ */ +ul.nav-tabs { + margin: 0; +} + +p.deprecated span{ + color: #ff0000; + font-weight: bold; + text-decoration: underline; +} + +/* ------------------------------------------------------------------------------------------ + * Print + * ------------------------------------------------------------------------------------------ */ + +@media print { + + #sidenav, + #version, + #versions, + section .version, + section .versions { + display: none; + } + + #content { + margin-left: 0; + } + + a { + text-decoration: none; + color: inherit; + } + + a:after { + content: " [" attr(href) "] "; + } + + p { + color: #000000 + } + + pre { + background-color: #ffffff; + color: #000000; + padding: 10px; + border: #808080 1px solid; + border-radius: 6px; + position: relative; + margin: 10px 0 20px 0; + } + +} /* /@media print */ diff --git a/doc/fonts/glyphicons-halflings-regular.eot b/doc/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 000000000..b93a4953f Binary files /dev/null and b/doc/fonts/glyphicons-halflings-regular.eot differ diff --git a/doc/fonts/glyphicons-halflings-regular.svg b/doc/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 000000000..94fb5490a --- /dev/null +++ b/doc/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,288 @@ + + + \ No newline at end of file diff --git a/doc/fonts/glyphicons-halflings-regular.ttf b/doc/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 000000000..1413fc609 Binary files /dev/null and b/doc/fonts/glyphicons-halflings-regular.ttf differ diff --git a/doc/fonts/glyphicons-halflings-regular.woff b/doc/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 000000000..9e612858f Binary files /dev/null and b/doc/fonts/glyphicons-halflings-regular.woff differ diff --git a/doc/fonts/glyphicons-halflings-regular.woff2 b/doc/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 000000000..64539b54c Binary files /dev/null and b/doc/fonts/glyphicons-halflings-regular.woff2 differ diff --git a/doc/img/favicon.ico b/doc/img/favicon.ico new file mode 100644 index 000000000..c307a0439 Binary files /dev/null and b/doc/img/favicon.ico differ diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 000000000..d6347f26e --- /dev/null +++ b/doc/index.html @@ -0,0 +1,669 @@ + + + + +Loading...
+