mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-08-28 14:50:34 +02:00
new home page, add expiration date, add github login
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
flask
|
flask
|
||||||
pygithub==1.40
|
pygithub==1.40
|
||||||
Flask-gzip
|
Flask-gzip
|
||||||
|
Authlib
|
||||||
|
loginpass
|
||||||
|
Flask-Session
|
||||||
|
pymongo
|
||||||
@@ -3,6 +3,7 @@ import uuid
|
|||||||
import json
|
import json
|
||||||
import socket
|
import socket
|
||||||
import os
|
import os
|
||||||
|
from bson import json_util
|
||||||
try:
|
try:
|
||||||
from urllib import quote # Python 2.X
|
from urllib import quote # Python 2.X
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -13,11 +14,24 @@ import string
|
|||||||
import base64
|
import base64
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
# non standards, in requirements.txt
|
|
||||||
from flask import Flask, request, Markup, render_template, redirect, url_for, send_from_directory
|
|
||||||
from flask_gzip import Gzip
|
|
||||||
import github
|
|
||||||
|
|
||||||
|
# non standards, in requirements.txt
|
||||||
|
from flask import Flask, request, Markup, render_template, redirect, url_for, send_from_directory, session
|
||||||
|
from flask_session import Session
|
||||||
|
from flask_gzip import Gzip
|
||||||
|
import github
|
||||||
|
from authlib.flask.client import OAuth
|
||||||
|
# use loginpass to make OAuth connection simpler
|
||||||
|
from loginpass import create_flask_blueprint, GitHub
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def handle_authorize(remote, token, user_info):
|
||||||
|
session['user'] = {
|
||||||
|
'user': user_info,
|
||||||
|
'token': token
|
||||||
|
}
|
||||||
|
return redirect('/myrepo')
|
||||||
|
|
||||||
def clean_github_repository(repo):
|
def clean_github_repository(repo):
|
||||||
"""
|
"""
|
||||||
@@ -54,20 +68,24 @@ def istext(s, threshold=0.30):
|
|||||||
try:
|
try:
|
||||||
binary_length = float(len(s.translate(None, TEXT_CHARACTERS)))
|
binary_length = float(len(s.translate(None, TEXT_CHARACTERS)))
|
||||||
except TypeError:
|
except TypeError:
|
||||||
print("error")
|
|
||||||
translate_table = dict((ord(char), None) for char in TEXT_CHARACTERS)
|
translate_table = dict((ord(char), None) for char in TEXT_CHARACTERS)
|
||||||
binary_length = float(len(s.translate(str.maketrans(translate_table))))
|
binary_length = float(len(s.translate(str.maketrans(translate_table))))
|
||||||
# s is 'text' if less than 30% of its characters are non-text ones:
|
# s is 'text' if less than 30% of its characters are non-text ones:
|
||||||
return binary_length/len(s) <= threshold
|
return binary_length/len(s) <= threshold
|
||||||
|
|
||||||
|
|
||||||
class Anonymous_Github:
|
class Anonymous_Github:
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
github_token,
|
github_token,
|
||||||
host="127.0.0.1",
|
host="127.0.0.1",
|
||||||
port=5000,
|
port=5000,
|
||||||
config_dir='./repositories'):
|
config_dir='./repositories',
|
||||||
|
secret_key=None,
|
||||||
|
client_id=None,
|
||||||
|
client_secret=None):
|
||||||
self.github_token = github_token if github_token != "" else os.environ["GITHUB_AUTH_TOKEN"]
|
self.github_token = github_token if github_token != "" else os.environ["GITHUB_AUTH_TOKEN"]
|
||||||
|
self.secret_key = secret_key if secret_key != "" else os.environ["SECRET_KEY"]
|
||||||
|
self.client_id = client_id if client_id != "" else os.environ["GITHUB_CLIENT_ID"]
|
||||||
|
self.client_secret = client_secret if client_secret != "" else os.environ["GITHUB_CLIENT_SECRET"]
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
self.config_dir = config_dir
|
self.config_dir = config_dir
|
||||||
@@ -94,13 +112,27 @@ class Anonymous_Github:
|
|||||||
application.killurl = str(uuid.uuid4())
|
application.killurl = str(uuid.uuid4())
|
||||||
application.jinja_env.add_extension('jinja2.ext.do')
|
application.jinja_env.add_extension('jinja2.ext.do')
|
||||||
|
|
||||||
|
application.config.update(
|
||||||
|
SESSION_TYPE='filesystem',
|
||||||
|
SECRET_KEY=self.secret_key,
|
||||||
|
GITHUB_CLIENT_ID=self.client_id,
|
||||||
|
GITHUB_CLIENT_SECRET=self.client_secret,
|
||||||
|
GITHUB_CLIENT_KWARGS = {
|
||||||
|
'scope': 'repo'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Session(application)
|
||||||
|
oauth = OAuth(application)
|
||||||
|
github_bp = create_flask_blueprint(GitHub, oauth, handle_authorize)
|
||||||
|
application.register_blueprint(github_bp, url_prefix='/github')
|
||||||
|
|
||||||
@application.template_filter('remove_terms', )
|
@application.template_filter('remove_terms', )
|
||||||
def remove_terms(content, repository_configuration, word_boundaries=True, whole_urls=True):
|
def remove_terms(content, repository_configuration, word_boundaries=True, whole_urls=True):
|
||||||
"""
|
"""
|
||||||
remove the blacklisted terms from the content
|
remove the blacklisted terms from the content
|
||||||
:param content: the content to anonymize
|
:param content: the content to anonymize
|
||||||
:param repository_configuration: the configuration of the repository
|
:param repository_configuration: the configuration of the repository
|
||||||
:return: the anonimized content
|
:return: the anonymized content
|
||||||
"""
|
"""
|
||||||
repo = repository_configuration['repository']
|
repo = repository_configuration['repository']
|
||||||
if repo[-1] == '/':
|
if repo[-1] == '/':
|
||||||
@@ -141,8 +173,11 @@ class Anonymous_Github:
|
|||||||
if file.size > 1000000:
|
if file.size > 1000000:
|
||||||
return Markup("The file %s is too big to be anonymized (beyond 1MB, Github limit)" % (file.name))
|
return Markup("The file %s is too big to be anonymized (beyond 1MB, Github limit)" % (file.name))
|
||||||
if ".md" in file.name or file.name == file.name.upper() or "changelog" == file.name.lower():
|
if ".md" in file.name or file.name == file.name.upper() or "changelog" == file.name.lower():
|
||||||
|
gh = self.github
|
||||||
|
if 'token' in repository_configuration:
|
||||||
|
gh = github.Github(repository_configuration['token'])
|
||||||
return Markup("<div class='markdown-body'>%s</div>" % remove_terms(
|
return Markup("<div class='markdown-body'>%s</div>" % remove_terms(
|
||||||
self.github.render_markdown(file.decoded_content.decode('utf-8')),
|
gh.render_markdown(file.decoded_content.decode('utf-8')),
|
||||||
repository_configuration))
|
repository_configuration))
|
||||||
if ".jpg" in file.name or ".png" in file.name or ".png" in file.name or ".gif" in file.name:
|
if ".jpg" in file.name or ".png" in file.name or ".png" in file.name or ".gif" in file.name:
|
||||||
index = file.name.index('.')
|
index = file.name.index('.')
|
||||||
@@ -175,6 +210,16 @@ class Anonymous_Github:
|
|||||||
return file, folder_content
|
return file, folder_content
|
||||||
return None, folder_content
|
return None, folder_content
|
||||||
|
|
||||||
|
@application.route('/myrepo', methods=['GET'])
|
||||||
|
def myrepo():
|
||||||
|
user = session.get('user', None)
|
||||||
|
g = github.Github(user['token']['access_token'])
|
||||||
|
repos = g.get_user().get_repos(sort="full_name")
|
||||||
|
for repo in repos:
|
||||||
|
repo.uuid = str(uuid.uuid4())
|
||||||
|
return render_template('newrepo.html', repos=repos)
|
||||||
|
|
||||||
|
|
||||||
@application.route('/repository/<id>/commit/<sha>', methods=['GET'])
|
@application.route('/repository/<id>/commit/<sha>', methods=['GET'])
|
||||||
def commit(id, sha):
|
def commit(id, sha):
|
||||||
"""
|
"""
|
||||||
@@ -186,9 +231,12 @@ class Anonymous_Github:
|
|||||||
if not os.path.exists(config_path):
|
if not os.path.exists(config_path):
|
||||||
return render_template('404.html'), 404
|
return render_template('404.html'), 404
|
||||||
with open(config_path) as f:
|
with open(config_path) as f:
|
||||||
data = json.load(f)
|
data = json.load(f, object_hook=json_util.object_hook)
|
||||||
(username, repo, branch) = clean_github_repository(data['repository'])
|
(username, repo, branch) = clean_github_repository(data['repository'])
|
||||||
g_repo = self.github.get_repo("%s/%s" % (username, repo))
|
gh = self.github
|
||||||
|
if 'token' in data:
|
||||||
|
gh = github.Github(data['token'])
|
||||||
|
g_repo = gh.get_repo("%s/%s" % (username, repo))
|
||||||
commit = g_repo.get_commit(sha)
|
commit = g_repo.get_commit(sha)
|
||||||
return render_template('repo.html',
|
return render_template('repo.html',
|
||||||
repository=data,
|
repository=data,
|
||||||
@@ -292,7 +340,10 @@ class Anonymous_Github:
|
|||||||
or ".js" in current_file.name:
|
or ".js" in current_file.name:
|
||||||
content = remove_terms(content, repository_config)
|
content = remove_terms(content, repository_config)
|
||||||
if ".md" in current_file.name:
|
if ".md" in current_file.name:
|
||||||
content = remove_terms(self.github.render_markdown(content), repository_config)
|
gh = self.github
|
||||||
|
if 'token' in repository_config:
|
||||||
|
gh = github.Github(repository_config['token'])
|
||||||
|
content = remove_terms(gh.render_markdown(content), repository_config)
|
||||||
else:
|
else:
|
||||||
tree = files
|
tree = files
|
||||||
if type(tree) != list:
|
if type(tree) != list:
|
||||||
@@ -390,9 +441,18 @@ class Anonymous_Github:
|
|||||||
if not os.path.exists(config_path):
|
if not os.path.exists(config_path):
|
||||||
return render_template('404.html'), 404
|
return render_template('404.html'), 404
|
||||||
with open(config_path, 'r') as f:
|
with open(config_path, 'r') as f:
|
||||||
repository_configuration = json.load(f)
|
repository_configuration = json.load(f, object_hook=json_util.object_hook)
|
||||||
|
if 'expiration_date' in repository_configuration:
|
||||||
|
if repository_configuration['expiration_date'] > datetime.now(repository_configuration['expiration_date'].tzinfo):
|
||||||
|
if repository_configuration['expiration'] == 'redirect':
|
||||||
|
return redirect(repository_configuration['repository'])
|
||||||
|
elif repository_configuration['expiration'] == 'remove':
|
||||||
|
return render_template('404.html'), 404
|
||||||
(username, repo, branch) = clean_github_repository(repository_configuration['repository'])
|
(username, repo, branch) = clean_github_repository(repository_configuration['repository'])
|
||||||
g_repo = self.github.get_repo("%s/%s" % (username, repo))
|
gh = self.github
|
||||||
|
if 'token' in repository_configuration:
|
||||||
|
gh = github.Github(repository_configuration['token'])
|
||||||
|
g_repo = gh.get_repo("%s/%s" % (username, repo))
|
||||||
g_commit = None
|
g_commit = None
|
||||||
try:
|
try:
|
||||||
g_commit = g_repo.get_commit(branch)
|
g_commit = g_repo.get_commit(branch)
|
||||||
@@ -442,27 +502,40 @@ class Anonymous_Github:
|
|||||||
config_path = self.config_dir + "/" + id + "/config.json"
|
config_path = self.config_dir + "/" + id + "/config.json"
|
||||||
if os.path.exists(config_path):
|
if os.path.exists(config_path):
|
||||||
with open(config_path) as f:
|
with open(config_path) as f:
|
||||||
data = json.load(f)
|
data = json.load(f, object_hook=json_util.object_hook)
|
||||||
if repo_name == clean_github_repository(data['repository']):
|
if repo_name == clean_github_repository(data['repository']):
|
||||||
repo = data
|
repo = data
|
||||||
|
return render_template('newversion.html', repo=repo)
|
||||||
return render_template('index.html', repo=repo)
|
|
||||||
|
|
||||||
@application.route('/', methods=['POST'])
|
@application.route('/', methods=['POST'])
|
||||||
def add_repository():
|
def add_repository():
|
||||||
id = request.args.get('id', str(uuid.uuid4()))
|
id = request.args.get('id', str(uuid.uuid4()))
|
||||||
repo = request.form['githubRepository']
|
repo = request.form['githubRepository']
|
||||||
terms = request.form['terms']
|
terms = request.form['terms']
|
||||||
|
expiration_date = None
|
||||||
|
expiration = None
|
||||||
|
if 'expiration' in request.form:
|
||||||
|
expiration = request.form['expiration']
|
||||||
|
if 'expiration_date' in request.form:
|
||||||
|
expiration_date = datetime.strptime(request.form['expiration_date'], '%Y-%m-%d')
|
||||||
|
|
||||||
|
user = session.get('user', None)
|
||||||
|
|
||||||
config_path = self.config_dir + "/" + str(id)
|
config_path = self.config_dir + "/" + str(id)
|
||||||
if not os.path.exists(config_path):
|
if not os.path.exists(config_path):
|
||||||
os.mkdir(config_path)
|
os.mkdir(config_path)
|
||||||
with open(config_path + "/config.json", 'w') as outfile:
|
with open(config_path + "/config.json", 'w') as outfile:
|
||||||
|
token = None
|
||||||
|
if user is not None:
|
||||||
|
token = user['token']['access_token']
|
||||||
json.dump({
|
json.dump({
|
||||||
"id": id,
|
"id": id,
|
||||||
"repository": repo,
|
"repository": repo,
|
||||||
"terms": terms.splitlines()
|
"terms": terms.splitlines(),
|
||||||
}, outfile)
|
"token": token,
|
||||||
|
"expiration_date": expiration_date,
|
||||||
|
"expiration": expiration
|
||||||
|
}, outfile, default=json_util.default)
|
||||||
return redirect(url_for('repository', id=id))
|
return redirect(url_for('repository', id=id))
|
||||||
|
|
||||||
return application
|
return application
|
||||||
@@ -474,6 +547,9 @@ class Anonymous_Github:
|
|||||||
def initParser():
|
def initParser():
|
||||||
parser = argparse.ArgumentParser(description='Start Anonymous Github')
|
parser = argparse.ArgumentParser(description='Start Anonymous Github')
|
||||||
parser.add_argument('-token', required=True, help='GitHub token')
|
parser.add_argument('-token', required=True, help='GitHub token')
|
||||||
|
parser.add_argument('-secret', required=True, help='App secret')
|
||||||
|
parser.add_argument('-client_id', required=True, help='GitHub aouth client id')
|
||||||
|
parser.add_argument('-client_secret', required=True, help='GitHub aouth client secret')
|
||||||
parser.add_argument('-host', help='The hostname', default="127.0.0.1")
|
parser.add_argument('-host', help='The hostname', default="127.0.0.1")
|
||||||
parser.add_argument('-port', help='The port of the application', default=5000)
|
parser.add_argument('-port', help='The port of the application', default=5000)
|
||||||
parser.add_argument('-config_dir', help='The repository that will contains the configuration files',
|
parser.add_argument('-config_dir', help='The repository that will contains the configuration files',
|
||||||
@@ -483,4 +559,4 @@ def initParser():
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
args = initParser()
|
args = initParser()
|
||||||
Anonymous_Github(github_token=args.token, host=args.host, port=args.port, config_dir=args.config_dir).run()
|
Anonymous_Github(github_token=args.token, host=args.host, port=args.port, config_dir=args.config_dir, secret_key=args.secret, client_id=args.client_id, client_secret=args.client_secret).run()
|
||||||
|
|||||||
@@ -1,3 +1,110 @@
|
|||||||
|
.fadeIn {
|
||||||
|
opacity: 1;
|
||||||
|
animation-name: fadeInOpacity;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
animation-timing-function: ease-in;
|
||||||
|
animation-duration: 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInOpacity {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea, select, input, button { outline: none; }
|
||||||
|
|
||||||
|
html,
|
||||||
|
body{
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
.view {
|
||||||
|
width: 100%;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-nav-collapse {
|
||||||
|
background: #4a507b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
box-shadow: 0 2px 5px 0 rgba(0,0,0,.16), 0 2px 10px 0 rgba(0,0,0,.12);
|
||||||
|
font-weight: 300;
|
||||||
|
transition: background-color 0.5s ease;
|
||||||
|
}
|
||||||
|
.navbar .nav-link.nav-icon {
|
||||||
|
padding: 0 .5rem;
|
||||||
|
}
|
||||||
|
.navbar .nav-link .fa {
|
||||||
|
font-size: 30px;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
.navbar:not(.top-nav-collapse) {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991px) {
|
||||||
|
.navbar:not(.top-nav-collapse) {
|
||||||
|
background: #4a507b !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rgba-gradient {
|
||||||
|
background: -moz-linear-gradient(45deg, rgba(51, 51, 51, 0.82), rgba(13, 17, 198, 0.69) 100%);
|
||||||
|
background: -webkit-linear-gradient(45deg, rgba(51, 51, 51, 0.82), rgba(13, 17, 198, 0.69) 100%);
|
||||||
|
background: linear-gradient(to 45deg, rgba(51, 51, 51, 0.82), rgba(13, 17, 198, 0.69) 100%);
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.white_border, .black_border {
|
||||||
|
border: 1px solid white;
|
||||||
|
padding: 7px;
|
||||||
|
background: transparent;
|
||||||
|
color: white;
|
||||||
|
min-width: 115px;
|
||||||
|
}
|
||||||
|
a.white_border, a.white_border:hover, a.black_border, a.black_border:hover {
|
||||||
|
padding: 10px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.white_border:focus, .black_border:focus {
|
||||||
|
background: #333333;
|
||||||
|
border: 1px solid #333333;
|
||||||
|
}
|
||||||
|
.white_border::placeholder, .black_border::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||||
|
color: #cccccc;
|
||||||
|
opacity: 1; /* Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
.black_border {
|
||||||
|
border: 1px solid #333333;
|
||||||
|
}
|
||||||
|
a.black_border, a.black_border:hover {
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
.black_border::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||||
|
color: #666666;
|
||||||
|
opacity: 1; /* Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
.active .container {
|
||||||
|
transition: height 1s ease;
|
||||||
|
}
|
||||||
|
.add_form {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.active .add_form {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
.main {
|
.main {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
@@ -73,4 +180,19 @@
|
|||||||
border-right: 0;
|
border-right: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.repos {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.repo {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 3px 7px;
|
||||||
|
background: #fdfdfd;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-top: 0
|
||||||
|
}
|
||||||
|
.repo .options {
|
||||||
|
float: right;
|
||||||
}
|
}
|
||||||
+244
-47
@@ -4,59 +4,256 @@
|
|||||||
<!-- Required meta tags -->
|
<!-- Required meta tags -->
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<title>GitHub Anonymous</title>
|
<title>Anonymous GitHub</title>
|
||||||
<!-- Bootstrap CSS -->
|
<!-- Bootstrap CSS -->
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
|
||||||
|
|
||||||
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" type="text/css" />
|
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" type="text/css" />
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="main">
|
<!-- Main navigation -->
|
||||||
<div class="container-fluid">
|
<header class="d-flex">
|
||||||
<h1>Anonymous GitHub for Open-Science</h1>
|
<!-- Navbar -->
|
||||||
Code and documentation: <a href="https://github.com/tdurieux/anonymous_github/">https://github.com/tdurieux/anonymous_github/</a>
|
<nav class="navbar navbar-expand-lg navbar-dark fixed-top scrolling-navbar ">
|
||||||
<h2>Create an Anonymous GitHub repository</h2>
|
<div class="container">
|
||||||
<p>
|
<a class="navbar-brand" href="#">Anonymous GitHub</a>
|
||||||
Fill 1. the Github repo URL and 2. the word list (which can be updated afterwards).
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo02" aria-controls="navbarTogglerDemo02" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
The anonymization of the content is done by replacing all occurrences of words in a list by "XXX".
|
<span class="navbar-toggler-icon"></span>
|
||||||
The word list typically contains the institution name, author names, logins, etc...
|
</button>
|
||||||
The README is anonymized as well as all files of the repository. Even filenames are anonymized.
|
<div class="collapse navbar-collapse" id="navbarTogglerDemo02">
|
||||||
In a double-blind submission, put the anonymous repository URL (e.g. <a href="http://anonymous.4open.science/repository/840c8c57-3c32-451e-bf12-0e20be300389/">http://anonymous.4open.science/repository/840c8c57-3c32-451e-bf12-0e20be300389/</a>).
|
<ul class="navbar-nav mr-auto smooth-scroll">
|
||||||
</p>
|
<li class="nav-item">
|
||||||
<form action="" method="post">
|
<a class="nav-link" href="#home">Home
|
||||||
<div class="form-group">
|
<span class="sr-only">(current)</span>
|
||||||
<label for="githubRepository">GitHub Repository</label>
|
</a>
|
||||||
<small id="githubRepositoryHelp" class="form-text text-muted">The github url to the repository that you want to anonymize.</small>
|
</li>
|
||||||
<input type="url" value="{{ repo.repository }}" class="form-control" name="githubRepository" id="githubRepository" aria-describedby="githubRepository" placeholder="GitHub Repository">
|
<li class="nav-item">
|
||||||
</div>
|
<a class="nav-link" href="#usage" data-offset="90">Usage</a>
|
||||||
<div class="form-group">
|
</li>
|
||||||
<label for="ignoredTerms">The text to remove from the repository will be replaced by XXX.</label>
|
<li class="nav-item">
|
||||||
<small id="ignoredTermsHelp" class="form-text text-muted">One term per line (case insensitive).</small>
|
<a class="nav-link" href="#features" data-offset="90">Features</a>
|
||||||
<textarea class="form-control" name="terms" id="ignoredTerms" rows="5">{{ repo.terms|join('\n') }}</textarea>
|
</li>
|
||||||
</div>
|
<li class="nav-item">
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<a class="nav-link" href="#about" data-offset="90">About</a>
|
||||||
</form>
|
</li>
|
||||||
{% if not repo %}
|
<li class="nav-item">
|
||||||
<h2>Edit an Anonymous GitHub repository</h2>
|
<a class="nav-link nav-icon" href="https://github.com/tdurieux/anonymous_github/" data-offset="30"><i class="fa fa-github" aria-hidden="true"></i></a>
|
||||||
<form action="" method="get">
|
</li>
|
||||||
<div class="form-group">
|
</ul>
|
||||||
<label for="name">Anonymous GitHub Repository</label>
|
|
||||||
<small id="nameHelp" class="form-text text-muted">The id of the Anonymous GitHub repository.</small>
|
|
||||||
<input class="form-control" name="id" id="name" aria-describedby="name" placeholder="Id Anonymous GitHub Repository">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="githubRepository">GitHub Repository</label>
|
|
||||||
<small id="githubRepositoryHelp" class="form-text text-muted">Password: the real Github url.</small>
|
|
||||||
<input type="url" class="form-control" name="githubRepository" id="githubRepository" aria-describedby="githubRepository" placeholder="GitHub Repository">
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<!-- Navbar -->
|
||||||
|
<!-- Full Page Intro -->
|
||||||
|
<div id="home" class="view rgba-gradient d-flex align-self-stretch justify-content-center align-items-center">
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="container px-md-3 px-sm-0">
|
||||||
|
<!--Grid row-->
|
||||||
|
<form action="" method="post">
|
||||||
|
<div class="row fadeIn main-options">
|
||||||
|
<!--Grid column-->
|
||||||
|
<div class="col-md-12 mb-4 white-text text-center fadeIn">
|
||||||
|
<h3 class="display-3 font-weight-bold white-text mb-0 pt-md-5 pt-5">Anonymous GitHub</h3>
|
||||||
|
<hr class="hr-light my-4 w-75">
|
||||||
|
<h4 class="subtext-header mt-2 mb-4">Double-blind your repository in 5 min!</h4>
|
||||||
|
<input id="url_input" type="text" placeholder="Repository URL..." name="githubRepository" class="white_border" value="{{ repo.repository }}" >
|
||||||
|
or
|
||||||
|
<a href="github/login" class="white_border">Login to GitHub</a>
|
||||||
|
or
|
||||||
|
<button id="edit-button" class="white_border">Edit your existing repository</button>
|
||||||
|
</div>
|
||||||
|
<!--Grid column-->
|
||||||
|
</div>
|
||||||
|
<div class="row add_form">
|
||||||
|
{% if not repo %}
|
||||||
|
<div class="col-md-12 mb-4 white-text fadeIn">
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
The repository has to be public, <a href="github/login">login to GitHub</a> for private repositories!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="col-md-12 mb-4 white-text fadeIn">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ignoredTerms">The text to remove from the repository will be replaced by XXX.</label>
|
||||||
|
<small id="ignoredTermsHelp" class="form-text text-muted">One term per line (case insensitive).</small>
|
||||||
|
<textarea class="form-control .form-control-lg" name="terms" id="ignoredTerms" rows="5">{{ repo.terms|join('\n') }}</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="expiration">Expiration options</label>
|
||||||
|
<select class="form-control" id="expiration" name="expiration">
|
||||||
|
<option value="never" {% if repo.expiration=="never" %} selected="selected"{% endif %}>Never</option>
|
||||||
|
<option value="redirect" {% if repo.expiration=="redirect" %} selected="selected"{% endif %}>Redirect to the GitHub repository</option>
|
||||||
|
<option value="remove" {% if repo.expiration=="remove" %} selected="selected"{% endif %}>Remove anonymized repository</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" id="expiration-date-form" style="display: none;">
|
||||||
|
<label for="date">Expiration date.</label>
|
||||||
|
<small class="form-text text-muted">When the anonymous repository.</small>
|
||||||
|
<input class="form-control .form-control-lg" type="date" name="expiration_date" id="date" value="{{ repo.expiration_date.date().isoformat() }}" />
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="white_border">Submit</button>`
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form class="row edit_form" style="display: none;">
|
||||||
|
<h2>Edit Anonymized Repository</h2>
|
||||||
|
<div class="col-md-12 mb-4 white-text fadeIn">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Repository ID</label>
|
||||||
|
<input class="form-control .form-control-lg" type="text" name="id" id="id"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Repository URL</label>
|
||||||
|
<input class="form-control .form-control-lg" type="url" name="githubRepository" id="url" value=""/>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="white_border">Submit</button>
|
||||||
|
<button id="edit_cancel" type="submit" class="white_border">Cancel</button>`
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<!--Grid row-->
|
||||||
|
</div>
|
||||||
|
<!-- Content -->
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Full Page Intro -->
|
||||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
</header>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
|
<!-- Main navigation -->
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
|
<!--Main Layout-->
|
||||||
|
<main>
|
||||||
|
<div class="container">
|
||||||
|
<!--Grid row-->
|
||||||
|
<div class="row py-5">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h2 id="usage">Usage</h2>
|
||||||
|
<p class="card-text mb-auto">
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
Fill the Github repo URL
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Complete the list of terms that will be anonymized.
|
||||||
|
<span class="text-muted">The anonymization of the content is done by replacing all occurrences of words in a list by "XXX".The word list typically contains the institution name, author names, logins, etc...</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Define if you want an expiration date for your anonymized repository.
|
||||||
|
You can keep it for ever, remove the repository after a specific date or redirect the user to the GitHub repository.
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
As result, a unique url is created with the content of your repository, for example, <a href="http://anonymous.4open.science/repository/840c8c57-3c32-451e-bf12-0e20be300389/">http://anonymous.4open.science/repository/840c8c57-3c32-451e-bf12-0e20be300389/</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<!--Grid column-->
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h2 id="features">Features</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="row no-gutters border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
|
||||||
|
<div class="col p-4 d-flex flex-column position-static">
|
||||||
|
<h3 class="mb-0">Anonymized</h3>
|
||||||
|
<p class="card-text mb-auto">
|
||||||
|
Anonymous GitHub Anonymizes the content of the repository but also hide the issues, pull-requests, history. This way you are sure that your repository stays anonymized.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="row no-gutters border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
|
||||||
|
<div class="col p-4 d-flex flex-column position-static">
|
||||||
|
<h3 class="mb-0">Always up-to-date</h3>
|
||||||
|
<p class="card-text mb-auto">
|
||||||
|
Anonymous GitHub follows to track of the changes on your repository and updates the anonymous version automatically.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="row no-gutters border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
|
||||||
|
<div class="col p-4 d-flex flex-column position-static">
|
||||||
|
<h3 class="mb-0">Fast</h3>
|
||||||
|
<p class="card-text mb-auto">
|
||||||
|
With Anonymous GitHub, it requires only 5min to anonymize your repository. No more time lost to create a anonymized version of your repository.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="row no-gutters border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
|
||||||
|
<div class="col p-4 d-flex flex-column position-static">
|
||||||
|
<h3 class="mb-0">Open-source</h3>
|
||||||
|
<p class="card-text mb-auto">
|
||||||
|
Anonymous GitHub is open-source, you can easily deploy it for your conference and simplify the life of your authors.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h2 id="about">Metrics</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="row no-gutters border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
|
||||||
|
<div class="col p-4 d-flex flex-column position-static">
|
||||||
|
<h3 class="mb-auto text-center">2609 Anonymized Repositories</h3>
|
||||||
|
<p class="card-text mb-auto">
|
||||||
|
<strong></strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--Grid column-->
|
||||||
|
</div>
|
||||||
|
<!--Grid row-->
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<!--Main Layout-->
|
||||||
|
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
|
||||||
|
<script>
|
||||||
|
if ($("#url_input")[0].value != "") {
|
||||||
|
$('.view').addClass('active')
|
||||||
|
}
|
||||||
|
$("#url_input").on('focus', e => {
|
||||||
|
$('.view').addClass('active')
|
||||||
|
})
|
||||||
|
if ($("#expiration")[0].value =='never') {
|
||||||
|
$("#expiration-date-form").hide();
|
||||||
|
} else {
|
||||||
|
$("#expiration-date-form").show();
|
||||||
|
}
|
||||||
|
$("#expiration").change(e => {
|
||||||
|
value = e.currentTarget.value;
|
||||||
|
if (value == 'never') {
|
||||||
|
$("#expiration-date-form").hide();
|
||||||
|
} else {
|
||||||
|
$("#expiration-date-form").show();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if ($(document).scrollTop() < 35) {
|
||||||
|
$('.navbar').removeClass('top-nav-collapse')
|
||||||
|
} else {
|
||||||
|
$('.navbar').addClass('top-nav-collapse')
|
||||||
|
}
|
||||||
|
$(document).scroll(e => {
|
||||||
|
if ($(document).scrollTop() < 35) {
|
||||||
|
$('.navbar').removeClass('top-nav-collapse')
|
||||||
|
} else {
|
||||||
|
$('.navbar').addClass('top-nav-collapse')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$('#edit_cancel').on('click', e=> {
|
||||||
|
e.preventDefault();
|
||||||
|
$(".edit_form").hide();
|
||||||
|
$('.main-options').show();
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
$('#edit-button').on('click', e=> {
|
||||||
|
e.preventDefault();
|
||||||
|
$('.view').removeClass('active')
|
||||||
|
$(".edit_form").show();
|
||||||
|
$('.main-options').hide();
|
||||||
|
$('#id').focus();
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<!-- Required meta tags -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<title>GitHub Anonymous</title>
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
|
||||||
|
|
||||||
|
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark fixed-top scrolling-navbar top-nav-collapse">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="#">Anonymous GitHub</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo02" aria-controls="navbarTogglerDemo02" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarTogglerDemo02">
|
||||||
|
<ul class="navbar-nav mr-auto smooth-scroll">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/">Home
|
||||||
|
<span class="sr-only">(current)</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link nav-icon" href="https://github.com/tdurieux/anonymous_github/" data-offset="30"><i class="fa fa-github" aria-hidden="true"></i></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="container" style="margin-top: 70px">
|
||||||
|
<div class="list-group">
|
||||||
|
{% for repo in repos %}
|
||||||
|
<div class="list-group-item list-group-item-action">
|
||||||
|
<div class="d-flex mb-12 justify-content-between">
|
||||||
|
<h5 class="mb-1">{{ repo.full_name }}</h5>
|
||||||
|
<small>{% if repo.private %} Private {% else %} Public {% endif %}</small>
|
||||||
|
</div>
|
||||||
|
{% if repo.description %}
|
||||||
|
<p class="mb-1">{{ repo.description }}</p>
|
||||||
|
{% endif %}
|
||||||
|
<div class="mb-1">
|
||||||
|
<a class="btn btn-primary anonymize-btn" href="/?githubRepository=https://github.com/{{ repo.full_name }}&id={{ repo.uuid }}">Anonymize</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.2.1.min.js" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$('.anonymize-btn').on('click', e => {
|
||||||
|
url = e.currentTarget.href;
|
||||||
|
$.post(url, url.substring(url.indexOf('?') + 1, url.length)+'&terms=', function () {
|
||||||
|
window.location.href =url;
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user