Commit 57ab0a24 authored by Chris Hines's avatar Chris Hines
Browse files

initial commit of web servcies associated with sshshare

parents
from flask import Flask, request
import flask
app = Flask(__name__)
@app.route("/download", methods=['GET'])
def download():
url = request.args.get('url')
import logging
logger = logging.debug("get creds from {}".format(url))
# response = flask.send_file("/home/chines/test_sftp/script", as_attachment=True, attachment_filename="script")
# return response
return use_ssh(url)
def get_credentials(url):
''' Given a secret URL, retrieve keys and uri '''
import os
import requests
s = requests.Session()
r = s.get(url)
data = r.json()
return(data['key'],data['cert'],data['uri'])
def use_ssh(url):
import os
(key,cert,uri) = get_credentials(url)
username,hostpath = uri.split('@')
print(uri)
host,path = hostpath.split(':')
filename=os.path.basename(path)
import subprocess
import os
# Start the agent
agent = subprocess.Popen(['ssh-agent'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
agentout,agenterr = agent.communicate()
environ = os.environ.copy()
for line in agentout.splitlines():
for cmd in line.split(b';'):
try:
(var,value) = cmd.split(b'=')
except:
var=None
value=None
if var is not None:
environ[var.decode()] = value.decode()
if var.decode() == 'SSH_AGENT_PID':
agentpid = int(value)
# Load the keys into the agent
keypath = save_keys(key,cert)
addp = subprocess.Popen(['ssh-add',keypath],stdout = subprocess.PIPE,stderr=subprocess.PIPE,env=environ)
stdout,stderr = addp.communicate()
# Star the open ssh process piping straing to the temporary file
# As an alternative, investigate the after_this_request decorator
import tempfile
f = tempfile.TemporaryFile()
sshp = subprocess.Popen(['ssh','-l',username,host,'cat',path],stdout = f ,stderr=None,stdin=None,env=environ)
sshp.wait()
rm_keys(keypath)
import signal
os.kill(agentpid,signal.SIGTERM)
f.seek(0)
response = flask.send_file(f, as_attachment=True, attachment_filename=filename)
return response
def save_keys(key,cert):
import tempfile
import os
keyf = tempfile.NamedTemporaryFile(mode='w',delete=False)
keypath = keyf.name
os.chmod(keypath,0o600)
keyf.write(key)
keyf.close()
with open(keypath+'-cert.pub','w') as certf:
certf.write(cert)
import time
time.sleep(1)
return keypath
def rm_keys(keypath):
''' Generate a Keypair and return its path on disk'''
import os
print("removing keys from {}".format(keypath))
try:
os.unlink(keypath)
except Exception as e:
pass
try:
os.unlink("{}.pub".format(keypath))
except:
pass
try:
os.unlink("{}-cert.pub".format(keypath))
except:
pass
from download import app as application
from sshshare_ws.database import init_db, db_session
init_db()
from download import app
import logging
logging.basicConfig(filename="download.log",format="%(asctime)s %(levelname)s:%(process)s: %(message)s")
logger=logging.getLogger()
logger.setLevel(logging.DEBUG)
#app.run(host='groups.me',debug=True,port=8083, ssl_context = context)
app.run(host='localhost',debug=True,port=8081)
from sshshare_ws import app
import logging
logging.basicConfig(filename="sshshare.log",format="%(asctime)s %(levelname)s:%(process)s: %(message)s")
logger=logging.getLogger()
logger.setLevel(logging.DEBUG)
#app.run(host='groups.me',debug=True,port=8083, ssl_context = context)
app.run(host='localhost',debug=True,port=8080)
"""A setuptools based setup module.
See:
https://packaging.python.org/en/latest/distributing.html
https://github.com/pypa/sampleproject
"""
# Always prefer setuptools over distutils
from setuptools import setup, find_packages
# To use a consistent encoding
from codecs import open
from os import path
here = path.abspath(path.dirname(__file__))
long_description = 'sshshare creates SSH certificates and manipulates your authorized keys file to allow them. sshshare_ws creates secret urls that you can give to someone else to retrieve the certificate and key. download allows users without openssh tools to pass the url returned to sshshare_ws to a proxy to download the file over http rather than ssh'
setup(
name='sshshare_ws',
version='0.0.1',
description=long_description,
long_description=long_description,
# The project's main homepage.
url='',
# Author details
author='Chris Hines',
author_email='help@massive.org.au',
# Choose your license
license='MIT',
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha',
# Indicate who your project is intended for
'Intended Audience :: Office workers',
'Topic :: Software Development :: Build Tools',
# Pick your license as you wish (should match "license" above)
'License :: OSI Approved :: MIT License',
# Specify the Python versions you support here. In particular, ensure
# that you indicate whether you support Python 2, Python 3 or both.
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
],
# What does your project relate to?
keywords='oauth2 OpenID Connect',
# You can just specify the packages manually here if your project is
# simple. Or you can use find_packages().
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
# Alternatively, if you want to distribute just a my_module.py, uncomment
# this:
# py_modules=["my_module"],
# List run-time dependencies here. These will be installed by pip when
# your project is installed. For an analysis of "install_requires" vs pip's
# requirements files see:
# https://packaging.python.org/en/latest/requirements.html
install_requires=[
'flask',
'flask_restful',
'sqlalchemy',
'wheel',
],
data_files = [('',[])],
# To provide executable scripts, use entry points in preference to the
# "scripts" keyword. Entry points provide cross-platform support and allow
# pip to create the appropriate form of executable for the target platform.
entry_points={
'console_scripts': [ 'dsu_wsgi_app=sshshare_ws:dsu_wsgi','proxy_wsgi_app=download:proxy_wsgi'],
'gui_scripts': [ ]
},
)
File added
import os
import sys
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
import flask
from flask_restful import Api, Resource
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'jhulaASDFjinzx'
api = Api(app)
from .database import Base
from .database import db_session
from . import models
from . import endpoints
from flask import make_response, request, current_app
@app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
if __name__ == '__main__':
app.run()
"""
"""
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///./sshshare.db', convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
# import all modules here that might define models so that
# they will be registered properly on the metadata. Otherwise
# you will have to import them first before calling init_db()
from . import models
Base.metadata.create_all(bind=engine)
from flask import Flask, request
app = Flask(__name__)
@app.route("/download", methods=['GET'])
def download()
url = request.args.get('url')
import os
(key,cert,uri) = get_credentials(url)
username,hostpath = uri.split('@')
print(uri)
host,path = hostpath.split(':')
filename=os.path.basename(path)
import subprocess
import os
# Start the agent
agent = subprocess.Popen(['ssh-agent'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
agentout,agenterr = agent.communicate()
environ = os.environ.copy()
for line in agentout.splitlines():
for cmd in line.split(b';'):
try:
(var,value) = cmd.split(b'=')
except:
var=None
value=None
if var is not None:
environ[var.decode()] = value.decode()
if var.decode() == 'SSH_AGENT_PID':
agentpid = int(value)
# Load the keys into the agent
keypath = save_keys(key,cert)
addp = subprocess.Popen(['ssh-add',keypath],stdout = subprocess.PIPE,stderr=subprocess.PIPE,env=environ)
stdout,stderr = addp.communicate()
# Star the open ssh process piping straing to the temporary file
# As an alternative, investigate the after_this_request decorator
import tempfile
f = tempfile.TemporaryFile()
sshp = subprocess.Popen(['ssh','-l',username,host,'cat',path],stdout = f ,stderr=None,stdin=None,env=environ)
sshp.wait()
rm_keys(keypath)
import signal
os.kill(agentpid,signal.SIGTERM)
f.seek(0)
response = flask.send_file(f, as_attachment=True, atttachment_filename=filename)
return response
def save_keys(key,cert):
import tempfile
import os
keyf = tempfile.NamedTemporaryFile(mode='w',delete=False)
keypath = keyf.name
os.chmod(keypath,0o600)
keyf.write(key)
keyf.close()
with open(keypath+'-cert.pub','w') as certf:
certf.write(cert)
import time
time.sleep(1)
return keypath
def rm_keys(keypath):
''' Generate a Keypair and return its path on disk'''
import os
print("removing keys from {}".format(keypath))
try:
os.unlink(keypath)
except Exception as e:
pass
try:
os.unlink("{}.pub".format(keypath))
except:
pass
try:
os.unlink("{}-cert.pub".format(keypath))
except:
pass
from sshshare_ws import app as application
from . import app, api
from .models import ShareData
from .database import db_session
from flask import url_for, session, redirect, request
import flask_restful
from flask_restful import Api, Resource
from sqlalchemy.exc import SQLAlchemyError
import logging
class ShareGetAPI(Resource):
def get(self, key):
import json
logger = logging.getLogger()
logger.debug("get data for key {}".format(key))
try:
sd = ShareData.query.get(key)
except:
return {}
logger.debug(sd.value)
data = json.loads(sd.value)
return data
class ShareStoreAPI(Resource):
def post(self):
import random
import string
import json
logger=logging.getLogger()
acceptedkey = False
postdata = request.get_json()
value = json.dumps(postdata)
logger.debug("post value {}".format(value))
while not acceptedkey:
key = ''.join(random.choices(string.ascii_uppercase + string.digits, k=16))
try:
newsd = ShareData(key=key,value=value)
db_session.add(newsd)
db_session.commit()
acceptedkey = True
except SQLAlchemyError as e:
logger.debug(e)
import traceback
logger.debug(traceback.format_exc())
return key
api.add_resource(ShareStoreAPI, '/share/', endpoint='share_store_ep')
api.add_resource(ShareGetAPI, '/share/<key>', endpoint='share_get_ep')
from .database import Base, db_session
from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Table
from sqlalchemy.orm import relationship
from datetime import datetime, timedelta
class ShareData(Base):
__tablename__ = 'ShareData'
key=Column(String,primary_key=True)
value=Column(String)
import requests
import random
import string
s = requests.Session()
cert=''.join(random.choices(string.ascii_uppercase + string.digits, k=16))
data ={'key':'123','cert':cert}
r = s.post('http://localhost:8080/share/',json=data)
print(r)
key = r.json()
d = s.get('http://localhost:8080/share/{}'.format(key))
retrieved_data = d.json()
print(data)
print(retrieved_data)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment