# -*- coding: utf-8 -*-
"""Test the checks that must pass for a request to go through."""

from flask.ext.hookserver import Hooks
from werkzeug.contrib.fixers import ProxyFix
import flask
import pytest


@pytest.fixture
def nocheck():
    """Test client for an app that ignores the IP and signature."""
    app = flask.Flask(__name__)
    app.config['DEBUG'] = True
    app.config['VALIDATE_IP'] = False
    app.config['VALIDATE_SIGNATURE'] = False
    return app.test_client()


@pytest.fixture(autouse=True)
def override_github(monkeypatch):
    """Prevent an actual request to GitHub."""
    monkeypatch.delattr('requests.sessions.Session.request')
    monkeypatch.setattr('flask_hookserver.load_github_hooks',
                        lambda: [u'192.30.252.0/22'])


@pytest.fixture
def app():
    app = flask.Flask(__name__)
    app.config['DEBUG'] = True
    Hooks(app)
    return app


def test_ipv4(app):
    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.config['VALIDATE_IP'] = True
    app.config['VALIDATE_SIGNATURE'] = False
    client = app.test_client()

    rv = client.post('/', headers={'X-Forwarded-For': '192.30.252.1'})
    assert rv.status_code == 404

    rv = client.post('/hooks', headers={'X-Forwarded-For': '192.30.252.1'})
    assert rv.status_code == 400

    rv = client.post('/hooks', headers={'X-Forwarded-For': '192.30.251.255'})
    assert b'Requests must originate from GitHub' in rv.data
    assert rv.status_code == 403

    rv = client.post('/hooks', headers={'X-Forwarded-For': '192.31.0.1'})
    assert b'Requests must originate from GitHub' in rv.data
    assert rv.status_code == 403


def test_ipv6(app):
    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.config['VALIDATE_IP'] = True
    app.config['VALIDATE_SIGNATURE'] = False
    client = app.test_client()

    rv = client.post('/', headers={'X-Forwarded-For': '::ffff:c01e:fc01'})
    assert rv.status_code == 404

    rv = client.post('/hooks', headers={'X-Forwarded-For': '::ffff:c01e:fc01'})
    assert rv.status_code == 400

    rv = client.post('/hooks', headers={'X-Forwarded-For': '::ffff:c01e:fbff'})
    assert b'Requests must originate from GitHub' in rv.data
    assert rv.status_code == 403

    rv = client.post('/hooks', headers={'X-Forwarded-For': '::ffff:c01f:1'})
    assert b'Requests must originate from GitHub' in rv.data
    assert rv.status_code == 403


def test_ignore_ip(app):
    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.config['VALIDATE_IP'] = False
    app.config['VALIDATE_SIGNATURE'] = False
    client = app.test_client()

    rv = client.post('/', headers={'X-Forwarded-For': '192.30.251.255'})
    assert rv.status_code == 404

    rv = client.post('/', headers={'X-Forwarded-For': '::ffff:c01e:fbff'})
    assert rv.status_code == 404


def test_signature(app):
    app.config['GITHUB_WEBHOOKS_KEY'] = b'Some key'
    app.config['VALIDATE_IP'] = False
    app.config['VALIDATE_SIGNATURE'] = True
    client = app.test_client()

    rv = client.post('/hooks', data='{}', content_type='application/json')
    assert b'Missing signature' in rv.data
    assert rv.status_code == 400

    headers = {
        'X-Hub-Signature': 'sha1=e1590250fd7dd7882185062d1ade5bef8cb4319c',
    }
    rv = client.post('/hooks', data='{}', content_type='application/json',
                     headers=headers)
    assert rv.status_code == 400

    headers = {
        'X-Hub-Signature': 'sha1=abc',
    }
    rv = client.post('/hooks', content_type='application/json', data='{}',
                     headers=headers)
    assert b'Wrong signature' in rv.data
    assert rv.status_code == 400


def test_ignore_signature(app):
    app.config['VALIDATE_IP'] = False
    app.config['VALIDATE_SIGNATURE'] = False
    client = app.test_client()

    rv = client.post('/')
    assert rv.status_code == 404

    headers = {
        'X-Hub-Signature': 'sha1=abc',
    }
    rv = client.post('/', content_type='application/json', data='{}',
                     headers=headers)
    assert rv.status_code == 404


def test_all_checks(app):
    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.config['GITHUB_WEBHOOKS_KEY'] = b'Some key'
    app.config['VALIDATE_IP'] = True
    app.config['VALIDATE_SIGNATURE'] = True
    client = app.test_client()

    sig = 'e1590250fd7dd7882185062d1ade5bef8cb4319c'
    headers = {
        'X-Forwarded-For': '::ffff:c01e:fc01',
        'X-Hub-Signature': 'sha1=' + sig,
        'X-GitHub-Event': 'ping',
        'X-GitHub-Delivery': 'abc',
    }
    rv = client.post('/hooks', content_type='application/json', data='{}',
                     headers=headers)
    assert rv.status_code == 200


def test_secret_key(app):
    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.config['SECRET_KEY'] = b'Some key'
    app.config['VALIDATE_IP'] = False
    app.config['VALIDATE_SIGNATURE'] = True
    client = app.test_client()

    sig = 'e1590250fd7dd7882185062d1ade5bef8cb4319c'
    headers = {
        'X-Hub-Signature': 'sha1=' + sig,
        'X-GitHub-Event': 'ping',
        'X-GitHub-Delivery': 'abc',
    }
    rv = client.post('/hooks', content_type='application/json', data='{}',
                     headers=headers)
    assert rv.status_code == 200


def test_different_url():
    app = flask.Flask(__name__)
    app.config['DEBUG'] = True
    Hooks(app, url='/some_url')

    app.config['VALIDATE_IP'] = False
    app.config['VALIDATE_SIGNATURE'] = False
    client = app.test_client()

    headers = {
        'X-GitHub-Event': 'ping',
        'X-GitHub-Delivery': 'abc',
    }
    rv = client.post('/some_url', content_type='application/json', data='{}',
                     headers=headers)
    assert rv.status_code == 200

    rv = client.post('/hooks')
    assert rv.status_code == 404


def test_missing_hook_data(app):
    app.config['VALIDATE_IP'] = False
    app.config['VALIDATE_SIGNATURE'] = False
    client = app.test_client()

    rv = client.post('/hooks')
    headers = {
        'X-GitHub-Delivery': 'abc',
    }
    rv = client.post('/hooks', content_type='application/json', data='{}',
                     headers=headers)
    assert b'Missing header: X-GitHub-Event' in rv.data
    assert rv.status_code == 400

    rv = client.post('/hooks')
    headers = {
        'X-GitHub-Event': 'ping',
    }
    rv = client.post('/hooks', content_type='application/json', data='{}',
                     headers=headers)
    assert b'Missing header: X-GitHub-Delivery' in rv.data
    assert rv.status_code == 400

    rv = client.post('/hooks')
    headers = {
        'X-GitHub-Event': 'ping',
        'X-GitHub-Delivery': 'abc',
    }
    rv = client.post('/hooks', content_type='application/json', data='',
                     headers=headers)
    assert b'Missing' not in rv.data
    assert rv.status_code == 400