TryGhost/Ghost

View on GitHub
ghost/admin/app/services/frontend.js

Summary

Maintainability
A
0 mins
Test Coverage
import Service, {inject as service} from '@ember/service';
import fetch from 'fetch';
import validator from 'validator';
import {inject} from 'ghost-admin/decorators/inject';

export default class FrontendService extends Service {
    @service settings;
    @service ajax;

    @inject config;

    _hasLoggedIn = false;
    _lastPassword = null;

    get hasPasswordChanged() {
        return this._lastPassword !== this.settings.password;
    }

    getUrl(path) {
        const siteUrl = new URL(this.config.blogUrl);
        const subdir = siteUrl.pathname.endsWith('/') ? siteUrl.pathname : `${siteUrl.pathname}/`;
        const fullPath = `${subdir}${path.replace(/^\//, '')}`;

        return `${siteUrl.origin}${fullPath}`;
    }

    async loginIfNeeded() {
        if (this.settings.isPrivate && (this.hasPasswordChanged || !this._hasLoggedIn)) {
            const privateLoginUrl = this.getUrl('/private/?r=%2F');
            this._lastPassword = this.settings.password;

            return fetch(privateLoginUrl, {
                method: 'POST',
                mode: 'cors',
                redirect: 'manual',
                credentials: 'include',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                body: `password=${this._lastPassword}`
            }).then(() => {
                this._hasLoggedIn = true;
            }).catch((e) => {
                // Safari will error when x-site tracking is prevented and frontend/admin are separate
                // we don't want to break anything else in that case so make it look like it succeeded
                console.error(e); // eslint-disable-line
                return true;
            });
        }
    }

    async fetch(urlOrPath, options) {
        await this.loginIfNeeded();
        let frontendUrl = urlOrPath;
        if (!validator.isURL(urlOrPath)) {
            frontendUrl = this.getUrl(urlOrPath);
        }
        return fetch(frontendUrl, {
            mode: 'cors',
            credentials: 'include',
            ...options
        });
    }
}