diff --git a/Makefile b/Makefile index bf486c3..34a7b98 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,7 @@ PYDEPS_COMMON = \ 'bddrest >= 5.1, < 6' \ 'bddcli >= 2.5.1, < 3' \ 'yhttp-dev >= 3.2.4' \ - 'requests' \ - 'libsass' + 'requests' # Assert the python-makelib version diff --git a/TODO.md b/TODO.md index 9cadeb0..8de6d01 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,5 @@ # Now +- dont's show oh, sorry! for directories without index.md - current dir - readme - screenshot diff --git a/examples/api/profiles-me.md b/examples/api/profiles-me.md new file mode 100644 index 0000000..d9e2e31 --- /dev/null +++ b/examples/api/profiles-me.md @@ -0,0 +1,263 @@ +# /profiles/me + +## Get authenticated user's profile + +### GET /profiles/me + +### Request Headers + +* Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc + +### CURL + +```bash +curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc" -- "$URL/profiles/me" +``` + +### Response: 200 OK + +#### Headers + +* content-length: 232 + +#### Body + +Content-Type: application/json + +```json +{"nickname":"god","nickname_isdirty":true,"timezone":"00:00","locale":null,"avatar":null,"roles":["god"],"created_at":"2024-08-22T03:30:00","modified_at":"2024-08-22T03:30:00","id":1,"email":"god@ayot.net","name":"God","phone":null} +``` + +--- + +## WHEN: Authorization header is not passed + +### GET /profiles/me + +### CURL + +```bash +curl -- "$URL/profiles/me" +``` + +### Response: 401 Unauthorized + +#### Headers + +* content-length: 703 + +--- + +## WHEN: User is already deleted + +### GET /profiles/me + +### CURL + +```bash +curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc" -- "$URL/profiles/me" +``` + +### Response: 404 Not Found + +#### Headers + +* content-length: 1160 + +## Updating profile by the owner + +### UPDATE /profiles/me + +### Form + +Name | Required | Type | Example +--- | --- | --- | --- +name | ? | ? | Bob +phone | ? | ? | +98 (912) 111 1111 + +### Request Headers + +* Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc + +### CURL + +```bash +curl -X UPDATE -F "name=Bob" -F "phone=+98 (912) 111 1111" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc" -- "$URL/profiles/me" +``` + +### Response: 200 OK + +#### Headers + +* content-length: 248 + +#### Body + +Content-Type: application/json + +```json +{"nickname":"god","nickname_isdirty":true,"timezone":"00:00","locale":null,"avatar":null,"roles":["god"],"created_at":"2024-08-22T03:30:00","modified_at":"2024-08-22T03:30:00","id":1,"email":"god@ayot.net","name":"Bob","phone":"+98 (912) 111 1111"} +``` + +--- + +## WHEN: Short nickname + +### UPDATE /profiles/me + +### Form + +Name | Required | Type | Example +--- | --- | --- | --- +nickname | ? | ? | + +### CURL + +```bash +curl -X UPDATE -F "nickname=" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc" -- "$URL/profiles/me" +``` + +### Response: 701 nickname: Length must be between 1 and 12 characters + +#### Headers + +* content-length: 1077 + +--- + +## WHEN: Long nickname + +### UPDATE /profiles/me + +### Form + +Name | Required | Type | Example +--- | --- | --- | --- +nickname | ? | ? | xxxxxxxxxxxxx + +### CURL + +```bash +curl -X UPDATE -F "nickname=xxxxxxxxxxxxx" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc" -- "$URL/profiles/me" +``` + +### Response: 701 nickname: Length must be between 1 and 12 characters + +#### Headers + +* content-length: 1077 + +--- + +## WHEN: Update nickname + +### UPDATE /profiles/me + +### Form + +Name | Required | Type | Example +--- | --- | --- | --- +nickname | ? | ? | Bob + +### CURL + +```bash +curl -X UPDATE -F "nickname=Bob" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc" -- "$URL/profiles/me" +``` + +### Response: 200 OK + +#### Headers + +* content-length: 249 + +#### Body + +Content-Type: application/json + +```json +{"nickname":"Bob","nickname_isdirty":false,"timezone":"00:00","locale":null,"avatar":null,"roles":["god"],"created_at":"2024-08-22T03:30:00","modified_at":"2024-08-22T03:30:00","id":1,"email":"god@ayot.net","name":"Bob","phone":"+98 (912) 111 1111"} +``` + +--- + +## WHEN: Update locale + +### UPDATE /profiles/me + +### Form + +Name | Required | Type | Example +--- | --- | --- | --- +locale | ? | ? | en-US + +### CURL + +```bash +curl -X UPDATE -F "locale=en-US" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc" -- "$URL/profiles/me" +``` + +### Response: 200 OK + +#### Headers + +* content-length: 252 + +#### Body + +Content-Type: application/json + +```json +{"nickname":"Bob","nickname_isdirty":false,"timezone":"00:00","locale":"en-US","avatar":null,"roles":["god"],"created_at":"2024-08-22T03:30:00","modified_at":"2024-08-22T03:30:00","id":1,"email":"god@ayot.net","name":"Bob","phone":"+98 (912) 111 1111"} +``` + +--- + +## WHEN: Update timezone + +### UPDATE /profiles/me + +### Form + +Name | Required | Type | Example +--- | --- | --- | --- +timezone | ? | ? | +03:30 + +### CURL + +```bash +curl -X UPDATE -F "timezone=+03:30" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc" -- "$URL/profiles/me" +``` + +### Response: 200 OK + +#### Headers + +* content-length: 253 + +#### Body + +Content-Type: application/json + +```json +{"nickname":"Bob","nickname_isdirty":false,"timezone":"+03:30","locale":"en-US","avatar":null,"roles":["god"],"created_at":"2024-08-22T03:30:00","modified_at":"2024-08-22T03:30:00","id":1,"email":"god@ayot.net","name":"Bob","phone":"+98 (912) 111 1111"} +``` + +--- + +## WHEN: Member deleted + +### UPDATE /profiles/me + +### CURL + +```bash +curl -X UPDATE -F "name=Bob" -F "phone=+98 (912) 111 1111" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzI0Mjg4NDAwLCJuaWNrbmFtZSI6ImdvZCIsInRpbWV6b25lIjoiMDA6MDAiLCJsb2NhbGUiOm51bGwsImF2YXRhciI6bnVsbCwicm9sZXMiOlsiZ29kIl19.oLfFxr1QNLYSfg-XDEc94-pFpXSzGCvjN0In58SH-kc" -- "$URL/profiles/me" +``` + +### Response: 404 Not Found + +#### Headers + +* content-length: 1163 + diff --git a/examples/api/tokens-google-cb.md b/examples/api/tokens-google-cb.md new file mode 100644 index 0000000..351e6b6 --- /dev/null +++ b/examples/api/tokens-google-cb.md @@ -0,0 +1,106 @@ +# /tokens/google/cb + +## Redirect back from google oauth2.0 server and login + +### GET /tokens/google/cb + +### Query Strings + +Name | Example +--- | --- +code | 4/0AX4XfWitAl4eZ2U7eJ7CYbFgl0HrKjUxrAuD5TiXfOV1ZHfcSWjxM1u6z_w8IZMXlLuJLg +scope | email+profile+https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile+openid +state | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjQ2OTgyODIsInJlZHVybCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImlkIjoiM2ZhYWQ0NDQ2YjAxY2UzNGNiOThjNGYyOWVkNWEwNTIwZDQxNGYwMDJlZmM2OTUzYmE3MjVkNWNkYjBjZTU3NCJ9.pkQ_qK19cDEJAWScWlGnyPijPRu0J-_TOOIGP1aXRi0 + +### Request Headers + +* Cookie: yhttp-csrf-token=3faad4446b01ce34cb98c4f29ed5a0520d414f002efc6953ba725d5cdb0ce574 + +### CURL + +```bash +curl -H "Cookie: yhttp-csrf-token=3faad4446b01ce34cb98c4f29ed5a0520d414f002efc6953ba725d5cdb0ce574" -- "$URL/tokens/google/cb?code=4%2F0AX4XfWitAl4eZ2U7eJ7CYbFgl0HrKjUxrAuD5TiXfOV1ZHfcSWjxM1u6z_w8IZMXlLuJLg&scope=email%2Bprofile%2Bhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%2Bhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%2Bopenid&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjQ2OTgyODIsInJlZHVybCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImlkIjoiM2ZhYWQ0NDQ2YjAxY2UzNGNiOThjNGYyOWVkNWEwNTIwZDQxNGYwMDJlZmM2OTUzYmE3MjVkNWNkYjBjZTU3NCJ9.pkQ_qK19cDEJAWScWlGnyPijPRu0J-_TOOIGP1aXRi0" +``` + +### Response: 302 Found + +#### Headers + +* location: http://localhost:8080 +* set-cookie: yhttp-refresh-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicmVmcmVzaCI6dHJ1ZSwiZXhwIjoxNzI3MjkwMjIyLCJyb2xlcyI6WyJnb2QiXX0.vAXoLxsLp8TnwZV5O50IPoiOU2T9LXw2GdO-FTV-T_Y; HttpOnly; Max-Age=2592000; Path=/tokens/google/cb; SameSite=Strict; Secure +* content-length: 0 + +--- + +## WHEN: Login again + +### GET /tokens/google/cb + +### CURL + +```bash +curl -H "Cookie: yhttp-csrf-token=3faad4446b01ce34cb98c4f29ed5a0520d414f002efc6953ba725d5cdb0ce574" -- "$URL/tokens/google/cb?code=4%2F0AX4XfWitAl4eZ2U7eJ7CYbFgl0HrKjUxrAuD5TiXfOV1ZHfcSWjxM1u6z_w8IZMXlLuJLg&scope=email%2Bprofile%2Bhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%2Bhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%2Bopenid&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjQ2OTgyODIsInJlZHVybCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImlkIjoiM2ZhYWQ0NDQ2YjAxY2UzNGNiOThjNGYyOWVkNWEwNTIwZDQxNGYwMDJlZmM2OTUzYmE3MjVkNWNkYjBjZTU3NCJ9.pkQ_qK19cDEJAWScWlGnyPijPRu0J-_TOOIGP1aXRi0" +``` + +### Response: 302 Found + +#### Headers + +* location: http://localhost:8080 +* set-cookie: yhttp-refresh-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicmVmcmVzaCI6dHJ1ZSwiZXhwIjoxNzI3MjkwMjIyLCJyb2xlcyI6WyJnb2QiXX0.vAXoLxsLp8TnwZV5O50IPoiOU2T9LXw2GdO-FTV-T_Y; HttpOnly; Max-Age=2592000; Path=/tokens/google/cb; SameSite=Strict; Secure +* content-length: 0 + +--- + +## WHEN: Google say 403 during key exchange + +### GET /tokens/google/cb + +### CURL + +```bash +curl -H "Cookie: yhttp-csrf-token=3faad4446b01ce34cb98c4f29ed5a0520d414f002efc6953ba725d5cdb0ce574" -- "$URL/tokens/google/cb?code=4%2F0AX4XfWitAl4eZ2U7eJ7CYbFgl0HrKjUxrAuD5TiXfOV1ZHfcSWjxM1u6z_w8IZMXlLuJLg&scope=email%2Bprofile%2Bhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%2Bhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%2Bopenid&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjQ2OTgyODIsInJlZHVybCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImlkIjoiM2ZhYWQ0NDQ2YjAxY2UzNGNiOThjNGYyOWVkNWEwNTIwZDQxNGYwMDJlZmM2OTUzYmE3MjVkNWNkYjBjZTU3NCJ9.pkQ_qK19cDEJAWScWlGnyPijPRu0J-_TOOIGP1aXRi0" +``` + +### Response: 401 Unauthorized + +#### Headers + +* content-length: 846 + +--- + +## WHEN: Google say 400 during key exchange + +### GET /tokens/google/cb + +### CURL + +```bash +curl -H "Cookie: yhttp-csrf-token=3faad4446b01ce34cb98c4f29ed5a0520d414f002efc6953ba725d5cdb0ce574" -- "$URL/tokens/google/cb?code=4%2F0AX4XfWitAl4eZ2U7eJ7CYbFgl0HrKjUxrAuD5TiXfOV1ZHfcSWjxM1u6z_w8IZMXlLuJLg&scope=email%2Bprofile%2Bhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%2Bhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%2Bopenid&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjQ2OTgyODIsInJlZHVybCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImlkIjoiM2ZhYWQ0NDQ2YjAxY2UzNGNiOThjNGYyOWVkNWEwNTIwZDQxNGYwMDJlZmM2OTUzYmE3MjVkNWNkYjBjZTU3NCJ9.pkQ_qK19cDEJAWScWlGnyPijPRu0J-_TOOIGP1aXRi0" +``` + +### Response: 401 Unauthorized + +#### Headers + +* content-length: 846 + +--- + +## WHEN: Token received from google is malformed + +### GET /tokens/google/cb + +### CURL + +```bash +curl -H "Cookie: yhttp-csrf-token=3faad4446b01ce34cb98c4f29ed5a0520d414f002efc6953ba725d5cdb0ce574" -- "$URL/tokens/google/cb?code=4%2F0AX4XfWitAl4eZ2U7eJ7CYbFgl0HrKjUxrAuD5TiXfOV1ZHfcSWjxM1u6z_w8IZMXlLuJLg&scope=email%2Bprofile%2Bhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%2Bhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%2Bopenid&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjQ2OTgyODIsInJlZHVybCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImlkIjoiM2ZhYWQ0NDQ2YjAxY2UzNGNiOThjNGYyOWVkNWEwNTIwZDQxNGYwMDJlZmM2OTUzYmE3MjVkNWNkYjBjZTU3NCJ9.pkQ_qK19cDEJAWScWlGnyPijPRu0J-_TOOIGP1aXRi0" +``` + +### Response: 401 Unauthorized + +#### Headers + +* content-length: 846 + diff --git a/examples/api/tokens-google-oauth2.md b/examples/api/tokens-google-oauth2.md new file mode 100644 index 0000000..e9eb471 --- /dev/null +++ b/examples/api/tokens-google-oauth2.md @@ -0,0 +1,92 @@ +# /tokens/google/oauth2 + +## Redirect user to google for oauth2.0 + +### GET /tokens/google/oauth2 + +### CURL + +```bash +curl -- "$URL/tokens/google/oauth2" +``` + +### Response: 302 Found + +#### Headers + +* location: https://accounts.google.com/o/oauth2/v2/auth?client_id=foobarbaz&response_type=code&scope=openid%20email%20profile&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Ftokens%2Fgoogle%2Fcb&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjQ2OTgyODIsInJlZHVybCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImlkIjoiZjgyNTEwOTMzYjAwMTliOTE4MmY2ZDAxNWEwODYxYWEzNzk1M2ZkZjViZWIxNzlmZGJlZTA0ODViMTQyOTlmOCJ9.z_vmLYQTw7PUeX3yhB7Sdec7puuqvH24ne5nR_hY4JY&access_type=offline +* set-cookie: yhttp-csrf-token=f82510933b0019b9182f6d015a0861aa37953fdf5beb179fdbee0485b14299f8; HttpOnly; Max-Age=60; Path=/tokens/google/oauth2; SameSite=Strict; Secure +* content-length: 0 + +--- + +## WHEN: Obtain OAuth2.0 token with refresh token + +### GET /tokens/google/oauth2 + +### Request Headers + +* cookie: yhttp-refresh-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicmVmcmVzaCI6dHJ1ZSwiZXhwIjoxNzI2ODgxMzcxLCJlbWFpbCI6ImdvZEBheW90Lm5ldCJ9.XcLGlUF65ZNZiyohF-h-mWJWm9zry9iGS22L8Wwf0Jc + +### CURL + +```bash +curl -H "cookie: yhttp-refresh-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicmVmcmVzaCI6dHJ1ZSwiZXhwIjoxNzI2ODgxMzcxLCJlbWFpbCI6ImdvZEBheW90Lm5ldCJ9.XcLGlUF65ZNZiyohF-h-mWJWm9zry9iGS22L8Wwf0Jc" -- "$URL/tokens/google/oauth2" +``` + +### Response: 302 Found + +#### Headers + +* location: https://accounts.google.com/o/oauth2/v2/auth?client_id=foobarbaz&response_type=code&scope=openid%20email%20profile&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Ftokens%2Fgoogle%2Fcb&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjQ2OTgyODIsInJlZHVybCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImlkIjoiM2ZhYWQ0NDQ2YjAxY2UzNGNiOThjNGYyOWVkNWEwNTIwZDQxNGYwMDJlZmM2OTUzYmE3MjVkNWNkYjBjZTU3NCJ9.pkQ_qK19cDEJAWScWlGnyPijPRu0J-_TOOIGP1aXRi0&access_type=offline&login_hint=god%40ayot.net +* set-cookie: yhttp-csrf-token=3faad4446b01ce34cb98c4f29ed5a0520d414f002efc6953ba725d5cdb0ce574; HttpOnly; Max-Age=60; Path=/tokens/google/oauth2; SameSite=Strict; Secure +* content-length: 0 + +--- + +## WHEN: `redurl` has invalid format + +### GET /tokens/google/oauth2 + +### Query Strings + +Name | Example +--- | --- +redurl | maformed + +### CURL + +```bash +curl -- "$URL/tokens/google/oauth2?redurl=maformed" +``` + +### Response: 702 redurl: Invalid Format + +#### Headers + +* content-length: 877 + +--- + +## WHEN: `redurl` is empty + +### GET /tokens/google/oauth2 + +### Query Strings + +Name | Example +--- | --- +redurl | + +### CURL + +```bash +curl -- "$URL/tokens/google/oauth2?redurl=" +``` + +### Response: 701 redurl: Length must be between 7 and 2048 characters + +#### Headers + +* content-length: 937 + diff --git a/setup.py b/setup.py index b55eaf7..e14cb86 100644 --- a/setup.py +++ b/setup.py @@ -21,6 +21,7 @@ 'markdown2', 'mako', 'pygments', + 'libsass', ] diff --git a/yhttp/markdown/styles/layout.sass b/yhttp/markdown/styles/layout.sass index 78f327a..0e3eb6d 100644 --- a/yhttp/markdown/styles/layout.sass +++ b/yhttp/markdown/styles/layout.sass @@ -1,11 +1,14 @@ html line-height: 2rem - + display: flex + align-content: stretch + align-items: stretch + flex-flow: row wrap body display: flex flex-direction: column - flex-wrap: nowrap + width: 100% header @@ -26,6 +29,22 @@ header margin: 0px +.content + width: 100% + display: flex + align-content: stretch + align-items: stretch + flex-direction: row + flex: 0 0 + aside + flex-shrink: 0 + #splitter + width: $gutter + flex: 0 0 $gutter + main + padding: $gutter ($gutter * 4) + width: 100% + footer font-size: .5rem padding: 0 ($gutter * 2) @@ -42,22 +61,6 @@ nav margin: 0 $gutter / 4 -.content - width: 100% - display: flex - align-items: stretch - flex-direction: row - flex: 1 0 - aside - flex-shrink: 0 - #splitter - width: $gutter - flex: 0 0 $gutter - main - padding: $gutter ($gutter * 4) - text-align: justify - - aside padding: $gutter ($gutter * 2) h1, h2, h3, h4, h5, h6 @@ -92,6 +95,9 @@ aside main + max-width: 100% + display: inline-block + overflow: hidden h1, h2, h3, h4, h5, h6 &:hover button opacity: 100% @@ -105,14 +111,20 @@ main opacity: 100% .codehilite - padding: ($gutter / 2) ($gutter / 2) ($gutter / 2) $gutter + padding: 0 margin: $gutter 0 - pre + position: relative &:hover button opacity: 100% button + position: absolute + right: $gutter / 2 + top: $gutter / 2 opacity: 50% - float: right &:hover opacity: 100% + pre + padding: $gutter * 2 + overflow-x: scroll + display: block