mirror of
https://github.com/fergalmoran/bitchmin.git
synced 2025-12-22 09:27:53 +00:00
armv7 build
This commit is contained in:
1
bitchmin-api/.gitignore
vendored
1
bitchmin-api/.gitignore
vendored
@@ -144,3 +144,4 @@ cython_debug/
|
||||
app.db
|
||||
bitchmin.db
|
||||
.idea/
|
||||
app/dashboard.cfg
|
||||
@@ -1 +1 @@
|
||||
BitchMin
|
||||
bitchmin-api
|
||||
27
bitchmin-api/.working/Dockerfile.alpine
Normal file
27
bitchmin-api/.working/Dockerfile.alpine
Normal file
@@ -0,0 +1,27 @@
|
||||
FROM python:3.7-alpine
|
||||
|
||||
COPY ./requirements.txt /requirements.txt
|
||||
|
||||
RUN apk update && \
|
||||
apk add --no-cache --virtual build-deps gcc python3-dev musl-dev bind-tools lapack libstdc++ && \
|
||||
apk --no-cache add --virtual .builddeps g++ gcc gfortran musl-dev lapack-dev && \
|
||||
apk add postgresql-dev && \
|
||||
pip install scipy && apk del .builddeps && rm -rf /root/.cache && \
|
||||
pip install -r requirements.txt
|
||||
|
||||
RUN pip install -r requirements.txt
|
||||
RUN pip install gunicorn
|
||||
|
||||
COPY app /app
|
||||
COPY migrations /migrations
|
||||
COPY server.py boot.sh ./
|
||||
RUN chmod +x boot.sh
|
||||
|
||||
ENV FLASK_ENV production
|
||||
ENV FLASK_APP server.py
|
||||
|
||||
RUN chown -R bitchmin:bitchmin ./
|
||||
USER bitchmin
|
||||
|
||||
EXPOSE 5000
|
||||
ENTRYPOINT ["./boot.sh"]
|
||||
@@ -1,30 +1,22 @@
|
||||
FROM python:3.7.4-alpine
|
||||
FROM python:3.7
|
||||
|
||||
RUN adduser -D bitchmin
|
||||
RUN mkdir /bitchmin
|
||||
WORKDIR /bitchmin
|
||||
COPY ./requirements.txt requirements.txt
|
||||
COPY ./requirements.txt /requirements.txt
|
||||
RUN apt update && \
|
||||
apt install libblas-dev && \
|
||||
pip install gunicorn
|
||||
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
RUN apk update && \
|
||||
apk add --no-cache --virtual build-deps gcc python3-dev musl-dev bind-tools && \
|
||||
apk add postgresql-dev && \
|
||||
pip install -r requirements.txt
|
||||
|
||||
|
||||
RUN python3.7 -m venv venv
|
||||
RUN venv/bin/pip install -r requirements.txt
|
||||
RUN venv/bin/pip install gunicorn
|
||||
|
||||
COPY app app
|
||||
COPY migrations migrations
|
||||
COPY app /app
|
||||
COPY migrations /migrations
|
||||
COPY server.py boot.sh ./
|
||||
RUN chmod +x boot.sh
|
||||
|
||||
ENV FLASK_ENV production
|
||||
ENV FLASK_APP server.py
|
||||
|
||||
RUN chown -R bitchmin:bitchmin ./
|
||||
USER bitchmin
|
||||
#RUN chown -R bitchmin:bitchmin ./
|
||||
#USER bitchmin
|
||||
|
||||
EXPOSE 5000
|
||||
ENTRYPOINT ["./boot.sh"]
|
||||
@@ -9,8 +9,9 @@ from flask_jwt_extended import JWTManager
|
||||
from flask_mail import Mail
|
||||
from flask_migrate import Migrate
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
import flask_monitoringdashboard as dashboard
|
||||
|
||||
from app.config import Config
|
||||
from app.conf import load_config
|
||||
from app.utils.encoders import IPAddressFieldEncoder
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -18,19 +19,20 @@ logger = logging.getLogger(__name__)
|
||||
db = SQLAlchemy()
|
||||
jwt = JWTManager()
|
||||
mail = Mail()
|
||||
|
||||
migrate = Migrate()
|
||||
|
||||
CELERY_TASK_LIST = [
|
||||
'app.tasks.hosts',
|
||||
]
|
||||
import flask_monitoringdashboard as dashboard
|
||||
|
||||
|
||||
def create_app(app_name='bitchmin', config_class=Config):
|
||||
def create_app(app_name='bitchmin'):
|
||||
logger.info('Creating app {}'.format(app_name))
|
||||
app = Flask(app_name)
|
||||
app.config.from_object(config_class)
|
||||
|
||||
app.config.from_object(
|
||||
load_config(os.environ.get('FLASK_ENV'))
|
||||
)
|
||||
|
||||
logger.info('Creating database {}'.format(app.config['SQLALCHEMY_DATABASE_URI']))
|
||||
db.init_app(app)
|
||||
@@ -69,6 +71,8 @@ def create_app(app_name='bitchmin', config_class=Config):
|
||||
app.logger.addHandler(file_handler)
|
||||
|
||||
app.json_encoder = IPAddressFieldEncoder
|
||||
dashboard.bind(app)
|
||||
dashboard.config.init_from(envvar='FLASK_MONITORING_DASHBOARD_CONFIG')
|
||||
|
||||
db.init_app(app)
|
||||
|
||||
@@ -95,6 +99,3 @@ def create_celery_app(app=None):
|
||||
|
||||
celery.Task = ContextTask
|
||||
return celery
|
||||
|
||||
|
||||
celery = create_celery_app()
|
||||
|
||||
@@ -1,38 +1,35 @@
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
from flask import jsonify, request
|
||||
from flask import jsonify, request, current_app
|
||||
from flask_jwt_extended import (
|
||||
create_access_token,
|
||||
jwt_refresh_token_required, create_refresh_token,
|
||||
get_current_user
|
||||
jwt_refresh_token_required, get_current_user
|
||||
)
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
||||
from app import db, jwt
|
||||
from app.api import api
|
||||
from app.config import Config
|
||||
from app.models.user import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def __create_token(user_id):
|
||||
expiry = timedelta(days=14) if Config.ISDEV else timedelta(minutes=15)
|
||||
return create_access_token(
|
||||
identity=user_id,
|
||||
expires_delta=expiry,
|
||||
fresh=True)
|
||||
|
||||
|
||||
@jwt.user_loader_callback_loader
|
||||
def user_loader_callback(identity):
|
||||
return User.by_id(identity)
|
||||
return db.session.query(User).get(identity)
|
||||
|
||||
|
||||
@api.route('/auth/register/', methods=('POST',))
|
||||
def register():
|
||||
data = request.get_json()
|
||||
user = User(**data)
|
||||
try:
|
||||
db.session.query(User).filter_by(email=user.email).one()
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'payload': 'User with email {} already exists.'.format(user.email)
|
||||
}), 409
|
||||
except NoResultFound:
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
return jsonify(user.to_dict()), 201
|
||||
@@ -45,8 +42,8 @@ def login():
|
||||
|
||||
if not user:
|
||||
return jsonify({'message': 'Invalid credentials', 'authenticated': False}), 401
|
||||
access_token = __create_token(user.id)
|
||||
refresh_token = create_refresh_token(user.id)
|
||||
access_token = user.create_token(timedelta(days=14) if current_app.config['ISDEV'] else timedelta(minutes=15))
|
||||
refresh_token = user.create_refresh_token()
|
||||
|
||||
return jsonify({
|
||||
'accessToken': access_token,
|
||||
@@ -61,8 +58,8 @@ def login():
|
||||
@jwt_refresh_token_required
|
||||
def token_refresh():
|
||||
user = get_current_user()
|
||||
access_token = __create_token(user.id)
|
||||
refresh_token = create_refresh_token(user.id)
|
||||
access_token = user.create_token()
|
||||
refresh_token = user.create_refresh_token()
|
||||
|
||||
return jsonify({
|
||||
'accessToken': access_token,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
@@ -17,9 +18,9 @@ from app.utils.iputils import is_valid_ip, is_valid_hostname
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@api.route('/dns/hosts')
|
||||
def get_hosts():
|
||||
return DnsZone.get_delete_put_post()
|
||||
@api.route('/dns/zones')
|
||||
def get_zones():
|
||||
return jsonify([zone.to_dict() for zone in db.session.query(DnsZone).all()]), 200
|
||||
|
||||
|
||||
@api.route('/dns/refresh', methods=['POST'])
|
||||
|
||||
18
bitchmin-api/app/conf/__init__.py
Normal file
18
bitchmin-api/app/conf/__init__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import os
|
||||
|
||||
|
||||
def load_config(mode=os.environ.get('FLASK_ENV')):
|
||||
"""Load config."""
|
||||
try:
|
||||
if mode == 'production':
|
||||
from .production import ProductionConfig
|
||||
return ProductionConfig
|
||||
elif mode == 'testing':
|
||||
from .testing import TestingConfig
|
||||
return TestingConfig
|
||||
else:
|
||||
from .development import DevelopmentConfig
|
||||
return DevelopmentConfig
|
||||
except ImportError:
|
||||
from .config import Config
|
||||
return Config
|
||||
@@ -4,17 +4,14 @@ from datetime import timedelta
|
||||
from dotenv import load_dotenv
|
||||
|
||||
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||
load_dotenv(os.path.join(basedir, '../.env'))
|
||||
load_dotenv(os.path.join(basedir, '../../.env'))
|
||||
|
||||
ISDEV = os.getenv('FLASK_ENV') == 'development'
|
||||
DEBUG_CONNECTION = 'postgresql+psycopg2://bitchmin:bitchmin@localhost/bitchmin'
|
||||
# DEBUG_CONNECTION = 'sqlite:///' + os.path.join(basedir, '../app.db')
|
||||
|
||||
|
||||
class Config(object):
|
||||
ISDEV = ISDEV
|
||||
SECRET_KEY = os.getenv('SECRET_KEY') or 'you-will-never-guess'
|
||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or DEBUG_CONNECTION
|
||||
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
LOG_TO_STDOUT = os.getenv('LOG_TO_STDOUT')
|
||||
@@ -37,21 +34,3 @@ class Config(object):
|
||||
'schedule': timedelta(minutes=15)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ProductionConfig(Config):
|
||||
DEBUG = False
|
||||
|
||||
|
||||
class StagingConfig(Config):
|
||||
DEVELOPMENT = True
|
||||
DEBUG = True
|
||||
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
DEVELOPMENT = True
|
||||
DEBUG = True
|
||||
|
||||
|
||||
class TestingConfig(Config):
|
||||
TESTING = True
|
||||
6
bitchmin-api/app/conf/development.py
Normal file
6
bitchmin-api/app/conf/development.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from .config import Config
|
||||
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
DEBUG = True
|
||||
SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://bitchmin:bitchmin@localhost/bitchmin'
|
||||
0
bitchmin-api/app/conf/init.py
Normal file
0
bitchmin-api/app/conf/init.py
Normal file
7
bitchmin-api/app/conf/production.py
Normal file
7
bitchmin-api/app/conf/production.py
Normal file
@@ -0,0 +1,7 @@
|
||||
import os
|
||||
|
||||
from .config import Config
|
||||
|
||||
|
||||
class ProductionConfig(Config):
|
||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
|
||||
6
bitchmin-api/app/conf/testing.py
Normal file
6
bitchmin-api/app/conf/testing.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from .config import Config
|
||||
|
||||
|
||||
class TestingConfig(Config):
|
||||
TESTING = True
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:////tmp/test.db'
|
||||
@@ -24,6 +24,12 @@ class DnsNameServer(db.Model, _BaseModelMixin, FlaskSerializeMixin):
|
||||
self.host = host
|
||||
self.ip = ip
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'host': self.host,
|
||||
'ip': self.ip
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class DnsZone(db.Model, _BaseModelMixin, FlaskSerializeMixin):
|
||||
@@ -48,6 +54,19 @@ class DnsZone(db.Model, _BaseModelMixin, FlaskSerializeMixin):
|
||||
|
||||
return self._create_serial()
|
||||
|
||||
def to_dict(self):
|
||||
ret_data = {
|
||||
'name': self.zone_name,
|
||||
'serial': self.serial,
|
||||
'admin': self.admin,
|
||||
'nameservers': [ns.to_dict() for ns in self.nameservers],
|
||||
'hosts': [host.to_dict() for host in self.hosts]
|
||||
}
|
||||
return ret_data
|
||||
|
||||
# TODO: FUCK!!
|
||||
admin = 'Ferg@lMoran.me'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
zone_name = db.Column(db.String(253), unique=True, nullable=False)
|
||||
serial = db.Column(db.Integer, default=_create_serial)
|
||||
@@ -66,15 +85,24 @@ class DnsHost(db.Model, _BaseModelMixin, FlaskSerializeMixin):
|
||||
|
||||
host = db.Column(db.String(255), unique=True, nullable=False)
|
||||
ip = db.Column(IPAddressType(255), nullable=False)
|
||||
type = db.Column(db.String(10), nullable=False)
|
||||
ttl = db.Column(db.Integer(), nullable=False)
|
||||
|
||||
def __init__(self, zone, host, ip):
|
||||
def __init__(self, zone, host, ip, ttl=30, record_type='A'):
|
||||
self.zone = zone
|
||||
self.host = host
|
||||
self.ip = ip
|
||||
self.ttl = ttl
|
||||
self.type = record_type
|
||||
pass
|
||||
|
||||
def to_dict(self):
|
||||
return dict(id=self.id, host=self.host, ip=self.ip)
|
||||
return {
|
||||
'name': self.host,
|
||||
'type': self.type,
|
||||
'ttl': self.ttl,
|
||||
'ip': self.ip,
|
||||
}
|
||||
|
||||
|
||||
# @event.listens_for(DnsZone.hosts, 'append')
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from flask_jwt_extended import create_access_token, create_refresh_token
|
||||
from sqlalchemy.orm import relationship
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
|
||||
@@ -49,6 +50,15 @@ class User(db.Model, _BaseModelMixin):
|
||||
|
||||
return user
|
||||
|
||||
def create_refresh_token(self):
|
||||
return create_refresh_token(self.id)
|
||||
|
||||
def create_token(self, expiry=timedelta(days=14)):
|
||||
return create_access_token(
|
||||
identity=self.id,
|
||||
expires_delta=expiry,
|
||||
fresh=True)
|
||||
|
||||
@classmethod
|
||||
def by_id(cls, user_id):
|
||||
return cls.query.get(user_id)
|
||||
|
||||
32
bitchmin-api/app/tests/conftest.py
Normal file
32
bitchmin-api/app/tests/conftest.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import pytest
|
||||
|
||||
from app import create_app
|
||||
from app import db as _db
|
||||
from seeder import DbSeeder
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def app(request):
|
||||
app = create_app()
|
||||
ctx = app.app_context()
|
||||
ctx.push()
|
||||
|
||||
def teardown():
|
||||
ctx.pop()
|
||||
|
||||
request.addfinalizer(teardown)
|
||||
return app
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def db(app, request):
|
||||
_db.app = app
|
||||
seeder = DbSeeder(_db)
|
||||
seeder.seed()
|
||||
|
||||
def teardown():
|
||||
seeder.teardown()
|
||||
|
||||
request.addfinalizer(teardown)
|
||||
|
||||
return _db
|
||||
12
bitchmin-api/app/tests/scaffold.py
Normal file
12
bitchmin-api/app/tests/scaffold.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from app import create_app
|
||||
from seeder import DbSeeder
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = create_app()
|
||||
ctx = app.app_context()
|
||||
ctx.push()
|
||||
from app import db
|
||||
|
||||
db.app = app
|
||||
|
||||
DbSeeder(db).seed()
|
||||
@@ -1,19 +1,10 @@
|
||||
import unittest
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
from app import db
|
||||
from app.models import DnsZone, User, DnsHost, DnsNameServer
|
||||
|
||||
|
||||
class Scaffolder(object):
|
||||
engine = create_engine(
|
||||
'postgresql+psycopg2://bitchmin:bitchmin@localhost/bitchmin',
|
||||
poolclass=StaticPool)
|
||||
Session = sessionmaker(bind=engine)
|
||||
session = Session()
|
||||
class DbSeeder(object):
|
||||
|
||||
def __init__(self, database):
|
||||
self._db = database
|
||||
|
||||
def _create_user(self):
|
||||
user = User(
|
||||
@@ -21,11 +12,11 @@ class Scaffolder(object):
|
||||
'Fergal Moran',
|
||||
'topsecret'
|
||||
)
|
||||
self.session.add(user)
|
||||
self._db.session.add(user)
|
||||
|
||||
def _create_zone(self):
|
||||
zone = DnsZone('bitchmints.com')
|
||||
self.session.add(zone)
|
||||
self._db.session.add(zone)
|
||||
return zone
|
||||
|
||||
def _create_nameservers(self, zone):
|
||||
@@ -36,7 +27,7 @@ class Scaffolder(object):
|
||||
'10.1.1.10{}'.format(i)
|
||||
|
||||
)
|
||||
self.session.add(ns)
|
||||
self._db.session.add(ns)
|
||||
|
||||
def _create_hosts(self, zone):
|
||||
for i in range(1, 11):
|
||||
@@ -45,24 +36,20 @@ class Scaffolder(object):
|
||||
'host-{}'.format(i),
|
||||
'10.1.1.{}'.format(i)
|
||||
)
|
||||
self.session.add(host)
|
||||
self._db.session.add(host)
|
||||
|
||||
def scaffold(self):
|
||||
db.metadata.drop_all(self.engine)
|
||||
db.metadata.create_all(self.engine)
|
||||
def seed(self):
|
||||
self._db.metadata.drop_all(self._db.engine)
|
||||
self._db.metadata.create_all(self._db.engine)
|
||||
|
||||
self._create_user()
|
||||
z = self._create_zone()
|
||||
self._create_nameservers(z)
|
||||
self._create_hosts(z)
|
||||
|
||||
self.session.commit()
|
||||
self.session.flush()
|
||||
self._db.session.commit()
|
||||
self._db.session.flush()
|
||||
|
||||
def teardown(self):
|
||||
db.metadata.drop_all(self.engine)
|
||||
self.engine.dispose()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Scaffolder().scaffold()
|
||||
self._db.metadata.drop_all(self._db.engine)
|
||||
self._db.engine.dispose()
|
||||
51
bitchmin-api/app/tests/test_auth_routes.py
Normal file
51
bitchmin-api/app/tests/test_auth_routes.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from app.models import User
|
||||
|
||||
|
||||
class TestAuthRoutes:
|
||||
def test_no_duplicate_registration(self, db, app) -> None:
|
||||
client = app.test_client()
|
||||
|
||||
request = {
|
||||
'email': 'fergal.moran@gmail.com',
|
||||
'full_name': 'Fergal Moran',
|
||||
'password': 'topsecret'
|
||||
}
|
||||
|
||||
rv = client.post(f"/auth/register/", json=request)
|
||||
assert "409" in rv.status
|
||||
|
||||
def test_registration(self, db, app) -> None:
|
||||
client = app.test_client()
|
||||
|
||||
request = {
|
||||
'email': 'fergal.moran+testuser@gmail.com',
|
||||
'full_name': 'Fergal Moran Test User',
|
||||
'password': 'topsecret2'
|
||||
}
|
||||
|
||||
rv = client.post(f"/auth/register/", json=request)
|
||||
assert "201" in rv.status
|
||||
|
||||
def test_login_fails(self, db, app) -> None:
|
||||
client = app.test_client()
|
||||
|
||||
request = {
|
||||
'email': 'fergal.moran@gmail.com',
|
||||
'password': 'asdasda'
|
||||
}
|
||||
|
||||
rv = client.post(f"/auth/login/", json=request)
|
||||
assert "401" in rv.status
|
||||
|
||||
def test_login_succeeds(self, db, app) -> None:
|
||||
client = app.test_client()
|
||||
|
||||
request = {
|
||||
'email': 'fergal.moran@gmail.com',
|
||||
'password': 'topsecret'
|
||||
}
|
||||
|
||||
rv = client.post(f"/auth/login/", json=request)
|
||||
assert "200" in rv.status
|
||||
@@ -1,37 +1,22 @@
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import func
|
||||
|
||||
from app.models import User, DnsZone, DnsNameServer, DnsHost
|
||||
from scaffolder import Scaffolder
|
||||
|
||||
|
||||
@pytest.fixture(scope="function") # or "module" (to teardown at a module level)
|
||||
def db():
|
||||
scaffolder = Scaffolder()
|
||||
scaffolder.teardown()
|
||||
scaffolder.scaffold()
|
||||
|
||||
yield scaffolder.session
|
||||
|
||||
scaffolder.teardown()
|
||||
|
||||
|
||||
class TestDatabaseUpdate:
|
||||
def test_load(self, db) -> None:
|
||||
assert db.query(User).count() == 1
|
||||
assert db.query(DnsZone).count() == 1
|
||||
assert db.query(DnsNameServer).count() == 2
|
||||
assert db.query(DnsHost).count() == 10
|
||||
assert db.session.query(User).count() == 1
|
||||
assert db.session.query(DnsZone).count() == 1
|
||||
assert db.session.query(DnsNameServer).count() == 2
|
||||
assert db.session.query(DnsHost).count() == 10
|
||||
|
||||
def test_serial_on_create(self, db) -> None:
|
||||
zone = db.query(DnsZone).first()
|
||||
zone = db.session.query(DnsZone).first()
|
||||
assert len(str(zone.serial)) == 10
|
||||
assert zone.get_serial_increment() == 10
|
||||
|
||||
def test_serial_on_add_host(self, db) -> None:
|
||||
zone = db.query(DnsZone).first()
|
||||
zone = db.session.query(DnsZone).first()
|
||||
serial = zone.get_serial_increment()
|
||||
|
||||
DnsHost(
|
||||
@@ -39,7 +24,7 @@ class TestDatabaseUpdate:
|
||||
host=str(uuid.uuid4()),
|
||||
ip='99.99.99.99'
|
||||
)
|
||||
db.commit()
|
||||
db.session.commit()
|
||||
"""
|
||||
Probably better to test that the new serial is > old serial...
|
||||
Not hugely important that it's only ONE more than it
|
||||
@@ -47,11 +32,10 @@ class TestDatabaseUpdate:
|
||||
assert zone.get_serial_increment() > serial
|
||||
|
||||
def test_serial_on_update_host(self, db) -> None:
|
||||
host = db.query(DnsHost).get(4)
|
||||
host = db.session.query(DnsHost).get(4)
|
||||
serial = host.zone.get_serial_increment()
|
||||
|
||||
host.ip = '99.99.99.99'
|
||||
db.commit()
|
||||
db.session.commit()
|
||||
|
||||
assert host.zone.get_serial_increment() > serial
|
||||
|
||||
20
bitchmin-api/app/tests/test_dns_routes.py
Normal file
20
bitchmin-api/app/tests/test_dns_routes.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import json
|
||||
from datetime import timedelta
|
||||
|
||||
from app.models import User
|
||||
|
||||
|
||||
class TestUserRoutes:
|
||||
|
||||
def test_get_hosts(self, db, app) -> None:
|
||||
client = app.test_client()
|
||||
rv = client.get(f"/dns/zones")
|
||||
assert "200" in rv.status
|
||||
zones = json.loads(rv.data)
|
||||
assert len(zones) == 1
|
||||
assert zones[0]['name'] == 'bitchmints.com'
|
||||
assert len(zones[0]['nameservers']) == 2
|
||||
assert zones[0]['nameservers'][0]['host'] == 'host-1'
|
||||
assert zones[0]['nameservers'][1]['host'] == 'host-2'
|
||||
assert zones[0]['nameservers'][0]['ip'] == '10.1.1.101'
|
||||
assert zones[0]['nameservers'][1]['ip'] == '10.1.1.102'
|
||||
12
bitchmin-api/app/tests/test_ping_routes.py
Normal file
12
bitchmin-api/app/tests/test_ping_routes.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from app.models import User
|
||||
|
||||
|
||||
class TestUserRoutes:
|
||||
|
||||
def test_user_get(self, db, app) -> None:
|
||||
client = app.test_client()
|
||||
rv = client.get(f"/ping")
|
||||
assert "200" in rv.status
|
||||
assert "pong!" in str(rv.data)
|
||||
14
bitchmin-api/app/tests/test_user_routes.py
Normal file
14
bitchmin-api/app/tests/test_user_routes.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from app.models import User
|
||||
|
||||
|
||||
class TestUserRoutes:
|
||||
|
||||
def test_user_get(self, db, app) -> None:
|
||||
client = app.test_client()
|
||||
user = db.session.query(User).first()
|
||||
token = user.create_token(timedelta(seconds=60))
|
||||
|
||||
rv = client.get(f"/user", headers={"Authorization": "Bearer {}".format(token)})
|
||||
assert "200" in rv.status
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/bin/sh
|
||||
source venv/bin/activate
|
||||
flask db upgrade
|
||||
exec gunicorn -b :5000 --access-logfile - --error-logfile - server:app
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
docker buildx build \
|
||||
--push \
|
||||
--platform linux/arm/v7,linux/amd64 \
|
||||
--platform linux/arm/v7 \
|
||||
-t fergalmoran/bitchmin-api .
|
||||
|
||||
BIN
bitchmin-api/flask_monitoringdashboard.db
Normal file
BIN
bitchmin-api/flask_monitoringdashboard.db
Normal file
Binary file not shown.
@@ -24,8 +24,8 @@ logger = logging.getLogger('alembic.env')
|
||||
from flask import current_app
|
||||
config.set_main_option(
|
||||
'sqlalchemy.url',
|
||||
str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%'))
|
||||
target_metadata = current_app.extensions['migrate'].db.metadata
|
||||
str(current_app.extensions['migrate']._db.engine.url).replace('%', '%%'))
|
||||
target_metadata = current_app.extensions['migrate']._db.metadata
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
ls
|
||||
rm -rf migrations || \
|
||||
rm bitchmin/bitchmin.db || \
|
||||
flask db init || \
|
||||
flask db migrate -m "Initial" || \
|
||||
flask db upgrade
|
||||
@@ -20,7 +20,9 @@ sqlalchemy
|
||||
requests
|
||||
IPy
|
||||
pydig
|
||||
tinder
|
||||
twilio
|
||||
flask_monitoringdashboard
|
||||
jinja2==2.11.1
|
||||
pytest
|
||||
pytest-flask
|
||||
pytest-flask-sqlalchemy
|
||||
@@ -1,7 +1,9 @@
|
||||
from flask_migrate import Migrate, upgrade
|
||||
from app import create_app, db
|
||||
from app import create_app, db, create_celery_app
|
||||
|
||||
app = create_app()
|
||||
celery = create_celery_app()
|
||||
|
||||
migrate = Migrate(app, db)
|
||||
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
BitchMin
|
||||
17
bitchmin-server/Dockerfile
Normal file
17
bitchmin-server/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM python:3.7-alpine
|
||||
|
||||
RUN apk add --update alpine-sdk
|
||||
|
||||
COPY requirements.txt /
|
||||
RUN pip install -r /requirements.txt
|
||||
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
ENV DNS_PORT 53
|
||||
ENV WORKER_PORT 10054
|
||||
|
||||
EXPOSE 53
|
||||
EXPOSE 10054
|
||||
|
||||
CMD [ "python", "./server.py" ]
|
||||
0
bitchmin-server/models/__init__.py
Normal file
0
bitchmin-server/models/__init__.py
Normal file
69
bitchmin-server/models/zone.py
Normal file
69
bitchmin-server/models/zone.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import json
|
||||
from types import SimpleNamespace
|
||||
|
||||
|
||||
class Zone(object):
|
||||
def __init__(self, serial, name, admin, hosts):
|
||||
self._serial = serial
|
||||
self._name = name
|
||||
self._admin = admin
|
||||
self._hosts = hosts
|
||||
|
||||
@staticmethod
|
||||
def from_json(data):
|
||||
try:
|
||||
zones = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
|
||||
return [Zone(
|
||||
x.serial,
|
||||
x.name,
|
||||
x.admin,
|
||||
{h.name: Host(
|
||||
h.ip,
|
||||
h.name,
|
||||
h.ttl,
|
||||
h.type
|
||||
) for h in x.hosts}
|
||||
) for x in zones]
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def admin(self):
|
||||
return self._admin
|
||||
|
||||
@property
|
||||
def serial(self):
|
||||
return self._serial
|
||||
|
||||
@property
|
||||
def hosts(self):
|
||||
return self._hosts
|
||||
|
||||
|
||||
class Host(object):
|
||||
|
||||
def __init__(self, ip, name, ttl, record_type):
|
||||
self._ip = ip
|
||||
self._name = name
|
||||
self._ttl = ttl
|
||||
self._record_type = record_type
|
||||
|
||||
@property
|
||||
def ip(self):
|
||||
return self._ip
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def ttl(self):
|
||||
return self._ttl
|
||||
|
||||
@property
|
||||
def record_type(self):
|
||||
return self._record_type
|
||||
@@ -1 +1,4 @@
|
||||
twisted
|
||||
pytest
|
||||
dnspython
|
||||
requests
|
||||
@@ -1,3 +1,4 @@
|
||||
import requests
|
||||
from twisted.internet import defer
|
||||
from twisted.names import dns, error
|
||||
import logging
|
||||
@@ -8,7 +9,8 @@ class InvalidZoneException(Exception):
|
||||
|
||||
|
||||
class Resolver:
|
||||
def _build_host(self, record_type, host, ip, ttl):
|
||||
@staticmethod
|
||||
def _build_host(record_type, host, ip, ttl):
|
||||
return {
|
||||
host: {
|
||||
'type': record_type,
|
||||
@@ -68,7 +70,7 @@ class MemoryResolver(Resolver):
|
||||
"""
|
||||
try:
|
||||
host = self._parse_host(zone, str(query.name))
|
||||
record = self._zones[zone]['hosts'][host]
|
||||
record = self._zones[zone].hosts[host]
|
||||
|
||||
if query.type == dns.NS:
|
||||
payload = dns.Record_NS(
|
||||
@@ -77,14 +79,14 @@ class MemoryResolver(Resolver):
|
||||
)
|
||||
else:
|
||||
payload = dns.Record_A(
|
||||
address=record['ip'],
|
||||
ttl=record['ttl']
|
||||
address=record.ip,
|
||||
ttl=record.ttl
|
||||
)
|
||||
|
||||
answer = dns.RRHeader(
|
||||
name=zone,
|
||||
payload=payload,
|
||||
ttl=record['ttl']
|
||||
ttl=record.ttl
|
||||
)
|
||||
|
||||
answers = [answer]
|
||||
|
||||
@@ -1,56 +1,40 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
import requests
|
||||
from twisted.internet import reactor
|
||||
from twisted.internet.endpoints import TCP4ServerEndpoint
|
||||
from twisted.names import client, dns, server
|
||||
|
||||
from models.zone import Zone
|
||||
from resolvers.memory_resolver import MemoryResolver
|
||||
from servers.worker_server import WorkerServerFactory
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
PORT = 10053
|
||||
WORKER_PORT = 10054
|
||||
PORT = os.environ.get('DNS_PORT') or 10053
|
||||
WORKER_PORT = os.environ.get('WORKER_PORT') or 10054
|
||||
API_HOST = os.environ.get('API_HOST') or 'http://localhost:5000/dns/zones'
|
||||
|
||||
|
||||
# TODO: This smells
|
||||
def get_zones():
|
||||
response = requests.get(API_HOST)
|
||||
zones = Zone.from_json(response.text)
|
||||
return {
|
||||
zone.name: zone
|
||||
for zone in zones}
|
||||
|
||||
|
||||
def main():
|
||||
zones = {
|
||||
'bitchmints.com': {
|
||||
'serial': 'BOOO',
|
||||
'admin': 'Ferg@lMoran.me',
|
||||
'nameservers': [
|
||||
'ns1.bitchmints.com',
|
||||
'ns2.bitchmints.com'
|
||||
],
|
||||
'hosts': {
|
||||
'ns1': {'type': 'A', 'ttl': 30, 'ip': '10.1.33.7'},
|
||||
'ns2': {'type': 'A', 'ttl': 30, 'ip': '10.1.33.8'},
|
||||
'host-1': {'type': 'A', 'ttl': 30, 'ip': '10.1.33.1'},
|
||||
'host-2': {'type': 'A', 'ttl': 30, 'ip': '10.1.33.1'},
|
||||
'host-3': {'type': 'A', 'ttl': 30, 'ip': '10.1.33.1'},
|
||||
'host-4': {'type': 'A', 'ttl': 30, 'ip': '10.1.33.1'},
|
||||
}
|
||||
},
|
||||
'fergl.ie': {
|
||||
'serial': 'BOOO',
|
||||
'admin': 'Ferg@lMoran.me',
|
||||
'nameservers': [
|
||||
'ns1.bitchmints.com',
|
||||
'ns2.bitchmints.com'
|
||||
],
|
||||
'hosts': {
|
||||
'farts': {'type': 'A', 'ttl': 30, 'ip': '10.1.33.8'},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zones = get_zones()
|
||||
memory_resolver = MemoryResolver(zones)
|
||||
|
||||
dns_factory = server.DNSServerFactory(
|
||||
clients=[
|
||||
memory_resolver,
|
||||
client.Resolver(resolv='/etc/resolv.conf')]
|
||||
|
||||
)
|
||||
|
||||
protocol = dns.DNSDatagramProtocol(controller=dns_factory)
|
||||
|
||||
0
bitchmin-server/tests/__init__.py
Normal file
0
bitchmin-server/tests/__init__.py
Normal file
14
bitchmin-server/tests/conftest.py
Normal file
14
bitchmin-server/tests/conftest.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def resolver():
|
||||
import dns.resolver
|
||||
|
||||
r = dns.resolver.Resolver()
|
||||
|
||||
r.nameservers = ['127.0.0.1']
|
||||
r.nameserver_ports = {
|
||||
'127.0.0.1': 10053
|
||||
}
|
||||
return r
|
||||
4
bitchmin-server/tests/test_lookups.py
Normal file
4
bitchmin-server/tests/test_lookups.py
Normal file
@@ -0,0 +1,4 @@
|
||||
def test_zones_exist(resolver) -> None:
|
||||
answer = resolver.resolve('host-1.bitchmints.com')
|
||||
|
||||
assert answer.address == '10.1.1.1'
|
||||
153
working/dns-test/.editorconfig
Normal file
153
working/dns-test/.editorconfig
Normal file
@@ -0,0 +1,153 @@
|
||||
###############################
|
||||
# Core EditorConfig Options #
|
||||
###############################
|
||||
|
||||
root = true
|
||||
|
||||
# All files
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# Code files
|
||||
[*.{cs,csx,vb,vbx}]
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
charset = utf-8-bom
|
||||
|
||||
###############################
|
||||
# .NET Coding Conventions #
|
||||
###############################
|
||||
|
||||
[*.{cs,vb}]
|
||||
# Organize usings
|
||||
dotnet_sort_system_directives_first = true
|
||||
dotnet_separate_import_directive_groups = false
|
||||
|
||||
# this. preferences
|
||||
dotnet_style_qualification_for_field = false:silent
|
||||
dotnet_style_qualification_for_property = false:silent
|
||||
dotnet_style_qualification_for_method = false:silent
|
||||
dotnet_style_qualification_for_event = false:silent
|
||||
|
||||
# Language keywords vs BCL types preferences
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||
dotnet_style_predefined_type_for_member_access = true:silent
|
||||
|
||||
# Parentheses preferences
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
||||
|
||||
# Modifier preferences
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
|
||||
# Expression-level preferences
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
|
||||
###############################
|
||||
# Naming Conventions #
|
||||
###############################
|
||||
|
||||
# Style Definitions
|
||||
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
||||
|
||||
# Use PascalCase for constant fields
|
||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
|
||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
|
||||
dotnet_naming_symbols.constant_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
|
||||
dotnet_naming_symbols.constant_fields.required_modifiers = const
|
||||
|
||||
dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
|
||||
dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
|
||||
dotnet_naming_rule.private_members_with_underscore.severity = suggestion
|
||||
dotnet_naming_symbols.private_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
|
||||
dotnet_naming_style.prefix_underscore.capitalization = camel_case
|
||||
dotnet_naming_style.prefix_underscore.required_prefix = _
|
||||
|
||||
|
||||
###############################
|
||||
# C# Code Style Rules #
|
||||
###############################
|
||||
|
||||
[*.cs]
|
||||
# var preferences
|
||||
csharp_style_var_for_built_in_types = true:silent
|
||||
csharp_style_var_when_type_is_apparent = true:silent
|
||||
csharp_style_var_elsewhere = true:silent
|
||||
|
||||
# Expression-bodied members
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
|
||||
# Pattern-matching preferences
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
|
||||
# Null-checking preferences
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
|
||||
# Modifier preferences
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
|
||||
|
||||
# Expression-level preferences
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_style_deconstructed_variable_declaration = true:suggestion
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
|
||||
###############################
|
||||
# C# Formatting Rules #
|
||||
###############################
|
||||
|
||||
# New line preferences
|
||||
csharp_new_line_before_open_brace = false
|
||||
csharp_new_line_before_else = false
|
||||
csharp_new_line_before_catch = false
|
||||
csharp_new_line_before_finally = false
|
||||
csharp_new_line_before_members_in_object_initializers = false
|
||||
csharp_new_line_before_members_in_anonymous_types = false
|
||||
csharp_new_line_between_query_expression_clauses = false
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_indent_labels = flush_left
|
||||
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
|
||||
# Wrapping preferences
|
||||
csharp_preserve_single_line_statements = true
|
||||
csharp_preserve_single_line_blocks = true
|
||||
27
working/dns-test/Program.cs
Normal file
27
working/dns-test/Program.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using DnsClient;
|
||||
using DnsClient.Protocol;
|
||||
|
||||
Console.WriteLine("Testing lookup");
|
||||
|
||||
var endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10053);
|
||||
var client = new LookupClient(endpoint);
|
||||
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
var host = $"host-{i}.bitchmints.com";
|
||||
Console.WriteLine($"Performing lookup for {host}");
|
||||
var results = client
|
||||
.Query(host, QueryType.A)
|
||||
.Answers
|
||||
.ARecords();
|
||||
|
||||
if (results.Any()) {
|
||||
foreach (var aRecord in results) {
|
||||
Console.WriteLine($"\tDomain: {aRecord.DomainName} resolved to {aRecord.Address}");
|
||||
}
|
||||
} else {
|
||||
Console.WriteLine($"\tDomain: {host} was not found");
|
||||
}
|
||||
}
|
||||
BIN
working/dns-test/bin/Debug/net5.0/DnsClient.dll
Executable file
BIN
working/dns-test/bin/Debug/net5.0/DnsClient.dll
Executable file
Binary file not shown.
BIN
working/dns-test/bin/Debug/net5.0/dns-test
Executable file
BIN
working/dns-test/bin/Debug/net5.0/dns-test
Executable file
Binary file not shown.
41
working/dns-test/bin/Debug/net5.0/dns-test.deps.json
Normal file
41
working/dns-test/bin/Debug/net5.0/dns-test.deps.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v5.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v5.0": {
|
||||
"dns-test/1.0.0": {
|
||||
"dependencies": {
|
||||
"DnsClient": "1.3.2"
|
||||
},
|
||||
"runtime": {
|
||||
"dns-test.dll": {}
|
||||
}
|
||||
},
|
||||
"DnsClient/1.3.2": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.1/DnsClient.dll": {
|
||||
"assemblyVersion": "1.3.2.0",
|
||||
"fileVersion": "1.3.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"dns-test/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"DnsClient/1.3.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-+3pku+O8VzuAirIezOhOa0rz0bK5SDtDgYUzVDbKxzFj9/zsMjvUAqS6kkxnUyX4d3L5d5MRR7gF2wLudODBYg==",
|
||||
"path": "dnsclient/1.3.2",
|
||||
"hashPath": "dnsclient.1.3.2.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
working/dns-test/bin/Debug/net5.0/dns-test.dll
Normal file
BIN
working/dns-test/bin/Debug/net5.0/dns-test.dll
Normal file
Binary file not shown.
BIN
working/dns-test/bin/Debug/net5.0/dns-test.pdb
Normal file
BIN
working/dns-test/bin/Debug/net5.0/dns-test.pdb
Normal file
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"additionalProbingPaths": [
|
||||
"/home/fergalm/.dotnet/store/|arch|/|tfm|",
|
||||
"/home/fergalm/.nuget/packages"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net5.0",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
working/dns-test/bin/Debug/net5.0/ref/dns-test.dll
Normal file
BIN
working/dns-test/bin/Debug/net5.0/ref/dns-test.dll
Normal file
Binary file not shown.
13
working/dns-test/dns-test.csproj
Normal file
13
working/dns-test/dns-test.csproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RootNamespace>dns_test</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DnsClient" Version="1.3.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v5.0", FrameworkDisplayName = "")]
|
||||
BIN
working/dns-test/obj/Debug/net5.0/apphost
Executable file
BIN
working/dns-test/obj/Debug/net5.0/apphost
Executable file
Binary file not shown.
23
working/dns-test/obj/Debug/net5.0/dns-test.AssemblyInfo.cs
Normal file
23
working/dns-test/obj/Debug/net5.0/dns-test.AssemblyInfo.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("dns-test")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("dns-test")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("dns-test")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
// Generated by the MSBuild WriteCodeFragment class.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
9f361857c6c60ffd4891f6a8e0304ff6fe4b537e
|
||||
@@ -0,0 +1,8 @@
|
||||
is_global = true
|
||||
build_property.TargetFramework = net5.0
|
||||
build_property.TargetPlatformMinVersion =
|
||||
build_property.UsingMicrosoftNETSdkWeb =
|
||||
build_property.ProjectTypeGuids =
|
||||
build_property.PublishSingleFile =
|
||||
build_property.IncludeAllContentForSelfExtract =
|
||||
build_property._SupportedPlatformList = Android,iOS,Linux,macOS,Windows
|
||||
BIN
working/dns-test/obj/Debug/net5.0/dns-test.assets.cache
Normal file
BIN
working/dns-test/obj/Debug/net5.0/dns-test.assets.cache
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
70cfeda8d1e9e2eb58e13e423a234b2e09b3c59b
|
||||
@@ -0,0 +1,18 @@
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/bin/Debug/net5.0/dns-test
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/bin/Debug/net5.0/dns-test.deps.json
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/bin/Debug/net5.0/dns-test.runtimeconfig.json
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/bin/Debug/net5.0/dns-test.runtimeconfig.dev.json
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/bin/Debug/net5.0/dns-test.dll
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/bin/Debug/net5.0/ref/dns-test.dll
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/bin/Debug/net5.0/dns-test.pdb
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/obj/Debug/net5.0/dns-test.csprojAssemblyReference.cache
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/obj/Debug/net5.0/dns-test.GeneratedMSBuildEditorConfig.editorconfig
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/obj/Debug/net5.0/dns-test.AssemblyInfoInputs.cache
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/obj/Debug/net5.0/dns-test.AssemblyInfo.cs
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/obj/Debug/net5.0/dns-test.csproj.CoreCompileInputs.cache
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/obj/Debug/net5.0/dns-test.dll
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/obj/Debug/net5.0/ref/dns-test.dll
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/obj/Debug/net5.0/dns-test.pdb
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/obj/Debug/net5.0/dns-test.genruntimeconfig.cache
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/bin/Debug/net5.0/DnsClient.dll
|
||||
/home/fergalm/dev/BitchMin/working/dns-test/obj/Debug/net5.0/dns-test.csproj.CopyComplete
|
||||
Binary file not shown.
BIN
working/dns-test/obj/Debug/net5.0/dns-test.dll
Normal file
BIN
working/dns-test/obj/Debug/net5.0/dns-test.dll
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
1e5a2e58d8a5d8f0bca0aaa4ee624df8facbe5c3
|
||||
BIN
working/dns-test/obj/Debug/net5.0/dns-test.pdb
Normal file
BIN
working/dns-test/obj/Debug/net5.0/dns-test.pdb
Normal file
Binary file not shown.
BIN
working/dns-test/obj/Debug/net5.0/ref/dns-test.dll
Normal file
BIN
working/dns-test/obj/Debug/net5.0/ref/dns-test.dll
Normal file
Binary file not shown.
66
working/dns-test/obj/dns-test.csproj.nuget.dgspec.json
Normal file
66
working/dns-test/obj/dns-test.csproj.nuget.dgspec.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"format": 1,
|
||||
"restore": {
|
||||
"/home/fergalm/dev/BitchMin/working/dns-test/dns-test.csproj": {}
|
||||
},
|
||||
"projects": {
|
||||
"/home/fergalm/dev/BitchMin/working/dns-test/dns-test.csproj": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "/home/fergalm/dev/BitchMin/working/dns-test/dns-test.csproj",
|
||||
"projectName": "dns-test",
|
||||
"projectPath": "/home/fergalm/dev/BitchMin/working/dns-test/dns-test.csproj",
|
||||
"packagesPath": "/home/fergalm/.nuget/packages/",
|
||||
"outputPath": "/home/fergalm/dev/BitchMin/working/dns-test/obj/",
|
||||
"projectStyle": "PackageReference",
|
||||
"configFilePaths": [
|
||||
"/home/fergalm/.nuget/NuGet/NuGet.Config"
|
||||
],
|
||||
"originalTargetFrameworks": [
|
||||
"net5.0"
|
||||
],
|
||||
"sources": {
|
||||
"https://api.nuget.org/v3/index.json": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"net5.0": {
|
||||
"targetAlias": "net5.0",
|
||||
"projectReferences": {}
|
||||
}
|
||||
},
|
||||
"warningProperties": {
|
||||
"warnAsError": [
|
||||
"NU1605"
|
||||
]
|
||||
}
|
||||
},
|
||||
"frameworks": {
|
||||
"net5.0": {
|
||||
"targetAlias": "net5.0",
|
||||
"dependencies": {
|
||||
"DnsClient": {
|
||||
"target": "Package",
|
||||
"version": "[1.3.2, )"
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
"net47",
|
||||
"net471",
|
||||
"net472",
|
||||
"net48"
|
||||
],
|
||||
"assetTargetFallback": true,
|
||||
"warn": true,
|
||||
"frameworkReferences": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"privateAssets": "all"
|
||||
}
|
||||
},
|
||||
"runtimeIdentifierGraphPath": "/home/fergalm/dotnet/sdk/5.0.100/RuntimeIdentifierGraph.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
working/dns-test/obj/dns-test.csproj.nuget.g.props
Normal file
18
working/dns-test/obj/dns-test.csproj.nuget.g.props
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/home/fergalm/.nuget/packages/</NuGetPackageRoot>
|
||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/home/fergalm/.nuget/packages/</NuGetPackageFolders>
|
||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">5.8.0</NuGetToolVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<SourceRoot Include="$([MSBuild]::EnsureTrailingSlash($(NuGetPackageFolders)))" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
6
working/dns-test/obj/dns-test.csproj.nuget.g.targets
Normal file
6
working/dns-test/obj/dns-test.csproj.nuget.g.targets
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
106
working/dns-test/obj/project.assets.json
Normal file
106
working/dns-test/obj/project.assets.json
Normal file
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"version": 3,
|
||||
"targets": {
|
||||
"net5.0": {
|
||||
"DnsClient/1.3.2": {
|
||||
"type": "package",
|
||||
"compile": {
|
||||
"lib/netstandard2.1/DnsClient.dll": {}
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.1/DnsClient.dll": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"DnsClient/1.3.2": {
|
||||
"sha512": "+3pku+O8VzuAirIezOhOa0rz0bK5SDtDgYUzVDbKxzFj9/zsMjvUAqS6kkxnUyX4d3L5d5MRR7gF2wLudODBYg==",
|
||||
"type": "package",
|
||||
"path": "dnsclient/1.3.2",
|
||||
"files": [
|
||||
".nupkg.metadata",
|
||||
".signature.p7s",
|
||||
"dnsclient.1.3.2.nupkg.sha512",
|
||||
"dnsclient.nuspec",
|
||||
"icon.png",
|
||||
"lib/net45/DnsClient.dll",
|
||||
"lib/net45/DnsClient.xml",
|
||||
"lib/net471/DnsClient.dll",
|
||||
"lib/net471/DnsClient.xml",
|
||||
"lib/netstandard1.3/DnsClient.dll",
|
||||
"lib/netstandard1.3/DnsClient.xml",
|
||||
"lib/netstandard2.0/DnsClient.dll",
|
||||
"lib/netstandard2.0/DnsClient.xml",
|
||||
"lib/netstandard2.1/DnsClient.dll",
|
||||
"lib/netstandard2.1/DnsClient.xml"
|
||||
]
|
||||
}
|
||||
},
|
||||
"projectFileDependencyGroups": {
|
||||
"net5.0": [
|
||||
"DnsClient >= 1.3.2"
|
||||
]
|
||||
},
|
||||
"packageFolders": {
|
||||
"/home/fergalm/.nuget/packages/": {}
|
||||
},
|
||||
"project": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "/home/fergalm/dev/BitchMin/working/dns-test/dns-test.csproj",
|
||||
"projectName": "dns-test",
|
||||
"projectPath": "/home/fergalm/dev/BitchMin/working/dns-test/dns-test.csproj",
|
||||
"packagesPath": "/home/fergalm/.nuget/packages/",
|
||||
"outputPath": "/home/fergalm/dev/BitchMin/working/dns-test/obj/",
|
||||
"projectStyle": "PackageReference",
|
||||
"configFilePaths": [
|
||||
"/home/fergalm/.nuget/NuGet/NuGet.Config"
|
||||
],
|
||||
"originalTargetFrameworks": [
|
||||
"net5.0"
|
||||
],
|
||||
"sources": {
|
||||
"https://api.nuget.org/v3/index.json": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"net5.0": {
|
||||
"targetAlias": "net5.0",
|
||||
"projectReferences": {}
|
||||
}
|
||||
},
|
||||
"warningProperties": {
|
||||
"warnAsError": [
|
||||
"NU1605"
|
||||
]
|
||||
}
|
||||
},
|
||||
"frameworks": {
|
||||
"net5.0": {
|
||||
"targetAlias": "net5.0",
|
||||
"dependencies": {
|
||||
"DnsClient": {
|
||||
"target": "Package",
|
||||
"version": "[1.3.2, )"
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
"net47",
|
||||
"net471",
|
||||
"net472",
|
||||
"net48"
|
||||
],
|
||||
"assetTargetFallback": true,
|
||||
"warn": true,
|
||||
"frameworkReferences": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"privateAssets": "all"
|
||||
}
|
||||
},
|
||||
"runtimeIdentifierGraphPath": "/home/fergalm/dotnet/sdk/5.0.100/RuntimeIdentifierGraph.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
working/dns-test/obj/project.nuget.cache
Normal file
10
working/dns-test/obj/project.nuget.cache
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dgSpecHash": "eyFn1mF0Ec0RODelM//pl87ne40rmd2/fm30g+WxWQ97TpqhUsZ79YryHC9MGUYH+wDk/epuUARQ5ofTUycO6w==",
|
||||
"success": true,
|
||||
"projectFilePath": "/home/fergalm/dev/BitchMin/working/dns-test/dns-test.csproj",
|
||||
"expectedPackageFiles": [
|
||||
"/home/fergalm/.nuget/packages/dnsclient/1.3.2/dnsclient.1.3.2.nupkg.sha512"
|
||||
],
|
||||
"logs": []
|
||||
}
|
||||
Reference in New Issue
Block a user