* 🔥 kill apiUrl helper, use urlFor helper instead
More consistency of creating urls.
Creates an easier ability to add config changes.
Attention: urlFor function is getting a little nesty, BUT that is for now wanted to make easier and centralised changes to the configs.
The url util need's refactoring anyway.
* 🔥 urlSSL
Remove all urlSSL usages.
Add TODO's for the next commit to re-add logic for deleted logic.
e.g.
- cors helper generated an array of url's to allow requests from the defined config url's -> will be replaced by the admin url if available
- theme handler prefered the urlSSL in case it was defined -> will be replaced by using the urlFor helper to get the blog url (based on the request secure flag)
The changes in this commit doesn't have to be right, but it helped going step by step.
The next commit is the more interesting one.
* 🔥✨ remove forceAdminSSL, add new admin url and adapt logic
I wanted to remove the forceAdminSSL as separate commit, but was hard to realise.
That's why both changes are in one commit:
1. remove forceAdminSSL
2. add admin.url option
- fix TODO's from last commits
- rewrite the ssl middleware!
- create some private helper functions in the url helper to realise the changes
- rename some wordings and functions e.g. base === blog (we have so much different wordings)
- i would like to do more, but this would end in a non readable PR
- this commit contains the most important changes to offer admin.url option
* 🤖 adapt tests
IMPORTANT
- all changes in the routing tests were needed, because each routing test did not start the ghost server
- they just required the ghost application, which resulted in a random server port
- having a random server port results in a redirect, caused by the ssl/redirect middleware
* 😎 rename check-ssl middleware
* 🎨 fix theme-handler because of master rebase
* 🎨🔥 do not store settings in config and make settings cache easier available
- remove remembering settings value in theme config
- if we need a cache value, we are asking the settings cache directly
- instead of settings.getSettingSync we use settings.cache.get
- added TODO:
- think about moving the settings cache out of api/settings
- we could create a folder named cache cache/settings
- this settings cache listens on model changes for settings
- decoupling
* 🔥 remove timezone from config
- no need to store in overrides config and in defaults settings
* 🎨 context object helper
- replace config.get('theme') by settings cache
* 🎨 replace config.get('theme') by settings.cache.get
* 🎨 adapt tests
* fixes from comments
refs #7488
- to be able to refactor the url configuration in ghost, we need to go step by step making this possible
- reduce the usage of forceAdminSSL
- add a urlFor('admin') helper, which returns the admin url + path e.g. http://my-blog.com/blog/ghost
- increase usage of urlFor helper
- do not expose getBaseUrl, use urlFor('home') (home === blog)
closes#7688
- Use `/favicon.ico` and `/favicon.png` in blog app. Depending on type of storage (custom upload = local file storage), serves either from storage adapter with `read()` method or reads the bytes via `fs`.
- Redirects requests for `favicon.ico` to `favicon.png` if custom `png` icon is uploaded and vice versa.
- Redirect requests for `favicon.png` to `favicon.ico` if default icon is used (in `core/shared`).
- Changes the `{{asset}}` helper for favicon to not serve from theme assets anymore. It will either be served the custom blog-icon or the default one.
- The `{{@blog.icon}}` helper renders the url of the **uploaded** blog icon. It won't render the default icon.
refs #7688
Adds an `uploads/icon/` endpoint to the api route to get a seperate entry point for blog icon validations. The blog icon validation will specifically check for images which have icon extensions (`.ico` & `.png`) and throw errors if:
- the icon file size is too big (>100kb)
- the icon is not a squaer
- the icon size is smaller than 32px
- the icon size is larger than 1000px
- the icon is not `.ico` or `.png` extension
TODOs for this PR:
- [X] get image dimensions
- [X] validate for image
- [X] size
- [X] form (must be square)
- [X] type
- [X] dimenstion (min 32px and max 1,000px)
- [X] return appropriate error messages
- [X] write tests
--------------------
TODOs for #7688:
- [X] Figure out, which favicon should be used (uploaded or default) -> #7713
- [ ] Serve and redirect the favicon for any browser requests, incl. redirects -> #7700 [WIP]
- [X] Upload favicon via `general/settings` and implement basic admin validations -> TryGhost/Ghost-Admin#397
- [X] Build server side validations -> this PR
closes#7766, refs #7579
- ensure we are using the correct brute keys
- ensure we are using req.ip as Ghost is configured with trust proxy option
- tidy up a little
refs #7666
Using `urlFor('home')` instead `config.get('url')` in Ghost.
When `urlFor('home', true)` returns the absolute adress of the blog as defined in the config.
Will always return a trailing `/`.
- see https://github.com/AdamPflug/express-brute/issues/45
- we have to handle two cases ATM: with and without callback
- in case we call the lib synchronous (which we should not actually), we will log the error so we get informed
no issue
- removes count from user checks model
- uses brute express brute with brute-knex adaptor to store persisted data on spam prevention
- implement brute force protection for password/token exchange, password resets and private blogging
* 🔥 remove User model functions
- validateToken
- generateToken
- resetPassword
- all this logic will re-appear in a different way
Token logic:
- was already extracted as separate PR, see https://github.com/TryGhost/Ghost/pull/7554
- we will use this logic in the controller, you will see in the next commits
Reset Password:
Was just a wrapper for calling the token logic and change the password.
We can reconsider keeping the function to call: changePassword and activate the status of the user - but i think it's fine to trigger these two actions from the controlling unit.
* 🔥 remove password reset tests from User model
- we already have unit tests for change password and the token logic
- i will re-check at the end if any test case is missing - but for now i will just burn the tests
* ✨ add token logic to controlling unit
generateResetToken endpoint
- the only change here is instead of calling the User model to generate a token, we generate the token via utils
- we fetch the user by email, and generate a hash and return
resetPassword endpoint
- here we have changed a little bit more
- first of all: we have added the validation check if the new passwords match
- a new helper method to extract the token informations
- the brute force security check, which can be handled later from the new bruteforce middleware (see TODO)
- the actual reset function is doing the steps: load me the user, compare the token, change the password and activate the user
- we can think of wrapping these steps into a User model function
- i was not sure about it, because it is actually part of the controlling unit
[ci skip]
* 🎨 tidy up
- jscs
- jshint
- naming functions
- fixes
* ✨ add a test for resetting the password
- there was none
- added a test to reset the password
* 🎨 add more token tests
- ensure quality
- ensure logic we had
* 🔥 remove compare new password check from User Model
- this part of controlling unit
* ✨ compare new passwords for user endpoint
- we deleted the logic in User Model
- we are adding the logic to controlling unit
* 🐛 spam prevention forgotten can crash
- no validation happend before this middleware
- it just assumes that the root key is present
- when we work on our API, we need to ensure that
1. pre validation happens
2. we call middlewares
3. ...
* 🎨 token translation key
* 🎨 rotation config
- every parameter is configureable
- increase default number of files to 100
* 🎨 ghost.log location
- example: content/logs/http___my_ghost_blog_com_ghost.log
- user can change the path to something custom by setting logging.path
* 🛠 add response-time as dependency
* 🎨 readable PrettyStream
- tidy up
- generic handling (was important to support more use cases, for example: logging.info({ anyKey: anyValue }))
- common log format
- less code 🕵🏻
* 🎨 GhostLogger cleanup
- remove setLoggers -> this function had too much of redundant code
- instead: add smart this.log function
- remove logging.request (---> GhostLogger just forwards the values, it doesn't matter if that is a request or not a request)
- make .warn .debug .info .error small and smart
* 🎨 app.js: add response time as middleware and remove logging.request
* 🎨 setStdoutStream and setFileStream
- redesign GhostLogger to add CustomLoggers very easily
----> Example CustomLogger
function CustomLogger(options) {
// Base iterates over defined transports
// EXAMPLE: ['stdout', 'elasticsearch']
Base.call(this, options);
}
util.inherits(...);
// OVERRIDE default stdout stream and your own!!!
CustomLogger.prototype.setStdoutStream = function() {}
// add a new stream
// get's called automatically when transport elasticsearch is defined
CustomLogger.prototype.setElasticsearchStream = function() {}
* 🎨 log into multiple file by default
- content/logs/domain.error.log --> contains only the errors
- content/logs/domain.log --> contains everything
- rotation for both files
* 🔥 remove logging.debug and use npm debug only
* ✨ shortcuts for mode and level
* 🎨 jshint/jscs
* 🎨 stdout as much as possible for an error
* 🎨 fix tests
* 🎨 remove req.ip from log output, remove response-time dependency
* 🎨 create middleware for logging
- added TODO to move logging middleware to ignition
* ✨ id for each error instance
- copy paste of ignition
- on purpose for now
- delete TODO, wohoo
- use id property instead of uid, see http://jsonapi.org/format/#errors
* 🕵🏻 remove TODO for decouple req.err
- can't find a nicer alternative solution
- added some more descriptions to code pieces in our error-handler
* 🎨 use uuid.v1
- timestamp based
* 🎨 one token endpoint
refs #7562
- delete /authentication/ghost
- Ghost-Admin will use /authentication/token for all use cases (password, refresh token and ghost.org authorization code)
- add new grant_type `authorization_code`
* 🎨 update comment description and remove spamPrevention.resetCounter
closes#4172, closes#6948, refs #7491, refs #7488, refs #7542, refs #7484
* 🎨 Co-locate all admin-related code in /admin
- move all the admin related code from controllers, routes and helpers into a single location
- add error handling middleware explicitly to adminApp
- re-order blogApp middleware to ensure the shared middleware is mounted after the adminApp
- TODO: rethink the structure of /admin, this should probably be an internal app
* 💄 Group global middleware together
- There are only a few pieces of middleware which are "global"
- These are needed for the admin, blog and api
- Everything else is only needed in one or two places
* ✨ Introduce a separate blogApp
- create a brand-new blogApp
- mount all blog/theme only middleware etc onto blogApp
- mount error handling on blogApp only
* 🎨 Separate error handling for HTML & API JSON
- split JSON and HTML error handling into separate functions
- re-introduce a way to not output the stack for certain errors
- add more tests around errors & an assertion framework for checking JSON Errors
- TODO: better 404 handling for static assets
Rationale:
The API is very different to the blog/admin panel:
- It is intended to only ever serve JSON, never HTML responses
- It is intended to always serve JSON
Meanwhile the blog and admin panel have no need for JSON errors,
when an error happens on those pages, we should serve HTML pages
which are nicely formatted with the error & using the correct template
* 🐛 Fix checkSSL to work for subapps
- in order to make this work on a sub app we need to use the pattern `req.originalUrl || req.url`
* 🔥 Get rid of decide-is-admin (part 1/2)
- delete decide-is-admin & tests
- add two small functions to apiApp and adminApp to set res.isAdmin
- mount checkSSL on all the apps
- TODO: deduplicate the calls to checkSSL by making blogApp a subApp :D
- PART 2/2: finish cleaning this up by removing it from where it's not needed and giving it a more specific name
Rationale:
Now that we have both an adminApp and an apiApp,
we can temporarily replace this weird path-matching middleware
with middleware that sets res.isAdmin for api & admin
* 🎨 Wire up prettyURLs on all Apps
- prettyURLs is needed for all requests
- it cannot be global because it has to live after asset middleware, and before routing
- this does not result in duplicate redirects, but does result in duplicate checks
- TODO: resolve extra middleware in stack by making blogApp a sub app
* ⏱ Add debug to API setup
* 🎨 Rename blogApp -> parentApp in middleware
* 🎨 Co-locate all blog-related code in /blog
- Move all of the blogApp code from middleware/index.js to blog/app.js
- Move routes/frontend.js to blog/routes.js
- Remove the routes/index.js and routes folder, this is empty now!
- @TODO is blog the best name for this? 🤔
- @TODO sort out the big hunk of asset-related mess
- @TODO also separate out the concept of theme from blog
* 🎉 Replace middleware index with server/app.js
- The final piece of the puzzle! 🎉🎈🎂
- We no longer have our horrendous middleware/index.js
- Instead, we have a set of app.js files, which all use a familiar pattern
* 💄 Error handling fixups
refs #4172
* 🎨 Use bodyParser only where it is needed
This is a pretty extreme optimisation, however in the interests of killing middleware/index.js it
seemed prudent to move towards not having in there that wasn't strictly necessary 😁
We should reassess how apps do this sort of thing, but it seems pretty sane to declare bodyParsing
if and only if it is necessary.
* 🎨 Move all API code to API router
* 🎨 Refactor API into an App, not just a router
- Apps have their own rendering engines, only the frontend & the admin panel need views
- The API should be JSON only, with minimal middleware
- Individual sections within the API could/should be treated as Routers
* 🎨 Flatten API middleware inclusion
- get rid of the weird middleware object
- move the api-only middleware into the middleware/api folder
* 💄 Combine slashes & uncapitalise middleware
- these bits of middleware belong together
- ideally they should be optimised
* 🎨 Move ghostLocals out of themeHandler
GhostLocals sets several important values which are needed for every part of the application,
admin, api and theme. Therefore, it doesn't make sense for it to be bundled in the themeHandler.
* 🐛 Fix the uncapitalise middleware
- Updated to make correct use of req.baseUrl, req.path, req.url & req.originalUrl
- Updated the tests to actually cover our weird cases
* 🎨 Move ghostVersion logic out of config
* 💄 Group static / asset-related middleware together
* 🔥 Remove /shared/ asset handling
- The 5 files which are located in `/shared/` are all handled by individual calls to `serveSharedFile`
- Therefore this code is redundant
refs #7116, refs #2001
- Changes the way Ghost errors are implemented to benefit from proper inheritance
- Moves all error definitions into a single file
- Changes the error constructor to take an options object, rather than needing the arguments to be passed in the correct order.
- Provides a wrapper so that any errors that haven't already been converted to GhostErrors get converted before they are displayed.
Summary of changes:
* 🐛 set NODE_ENV in config handler
* ✨ add GhostError implementation (core/server/errors.js)
- register all errors in one file
- inheritance from GhostError
- option pattern
* 🔥 remove all error files
* ✨ wrap all errors into GhostError in case of HTTP
* 🎨 adaptions
- option pattern for errors
- use GhostError when needed
* 🎨 revert debug deletion and add TODO for error id's
no issue
- unsued code:
- there are no public assets anymore, might need to use this instead of shared in future, but for now lets remove it to reduce confusion
- the `input password` box was incorrectly registered as an admin helper, thinking that was needed in order to render the default template. This isn't needed.
- apps:
- small structure & comment update to amp app
- moving input_password helper into private blogging app
- refactor helpers in subscribers app
- 🛠 add bunyan and prettyjson, remove morgan
- ✨ add logging module
- GhostLogger class that handles setup of bunyan
- PrettyStream for stdout
- ✨ config for logging
- @TODO: testing level fatal?
- ✨ log each request via GhostLogger (express middleware)
- @TODO: add errors to output
- 🔥 remove errors.updateActiveTheme
- we can read the value from config
- 🔥 remove 15 helper functions in core/server/errors/index.js
- all these functions get replaced by modules:
1. logging
2. error middleware handling for html/json
3. error creation (which will be part of PR #7477)
- ✨ add express error handler for html/json
- one true error handler for express responses
- contains still some TODO's, but they are not high priority for first implementation/integration
- this middleware only takes responsibility of either rendering html responses or return json error responses
- 🎨 use new express error handler in middleware/index
- 404 and 500 handling
- 🎨 return error instead of error message in permissions/index.js
- the rule for error handling should be: if you call a unit, this unit should return a custom Ghost error
- 🎨 wrap serve static module
- rule: if you call a module/unit, you should always wrap this error
- it's always the same rule
- so the caller never has to worry about what comes back
- it's always a clear error instance
- in this case: we return our notfounderror if serve static does not find the resource
- this avoid having checks everywhere
- 🎨 replace usages of errors/index.js functions and adapt tests
- use logging.error, logging.warn
- make tests green
- remove some usages of logging and throwing api errors -> because when a request is involved, logging happens automatically
- 🐛 return errorDetails to Ghost-Admin
- errorDetails is used for Theme error handling
- 🎨 use 500er error for theme is missing error in theme-handler
- 🎨 extend file rotation to 1w
refs #2001, #7116
- added debug and wired it up:
- across several key parts of the boot process
- throughout the middleware loading
- for requests
- at render points for key routes
issue #7452
Remote oauth2 authentication with Ghost.org.
This PR supports:
- oauth2 login or local login
- authentication on blog setup
- authentication on invite
- normal authentication
- does not contain many, many tests, but we'll improve in the next alpha weeks
no issue
- anonymous functions are hard to debug in memory traces etc
- having anonymous middleware functions makes it hard to inspect or debug the middleware stack (something I like to do)
- these 2 are the only ones atm, including all 3rd party middleware
refs #6982
- create config util fn: getContentPath
- we can later let the user change the folder names in contentPath
- get rid of custom/default storage paths
[ci skip]
no issue
Double slashes are treated as a HTTP calls as specified in [RFC1801](http://www.ietf.org/rfc/rfc1808.txt). Because of this behaviour the uncapitalise created an open redirect. By removing double slashes in the path we ensure open redirects cannot be created.
As an example, please click the following URL: https://dev.ghost.org///Google.com/.
This issue has been reported by pentesters of our product [LearningSpaces.io](http://learningspaces.io).
no issue
- Source out validation logic into a upload validation middleware for all upload types (csv, image, subscribers). This unit can be later used for Ghost 1.0 as a pre validation core unit.
- More usage of route tests than controller tests. These are use case tests, a use case only changes if the product changes
refs #6976, #7019, #7125
- Ensure maintenance mode flag is set back to what is in config.js rather than defaulted to false on boot
- Remove stack trace from 503 errors
- Add error message to 503 error
- Ensure error page is rendered for Ghost-Admin on reload with 503
closes#6948
- the hbs engine was never initialised when server starts
- when you request a page which does not exist, express jumps directly into the error handlers
- delete some dynamic hbs engine setters in theme handler
refs #6949
- Adds a new VersionMismatchError with status 400 (bad request)
- Adds middleware that checks the X-Ghost-Version header if it is provided
- If it is not provided, the middleware does nothing
- If it is provided, and the versions match, the middleware does nothing
- If it is provided, and the versions don't match, the middleware returns a VersionMismatchError
- Includes both unit and a functional test to prove the middleware works alone and as part of the whole system
Form:
- add confirm, location & referrer hidden fields
- add script to populate location & referrer
- add helper for creating the email field
- pass through input class and placeholder for email from top level form helper
- rename subscribe_form template & helper as it sounds more natural
- handle success and error cases differently
- improve error message display
- ensure useful data is passed back so that we can show nice messages
- check for honeypot value being filled out
- refactor error handler to set an error and always still render