diff --git a/bin/srv.py b/bin/srv.py index cb7c299..dda9bf6 100644 --- a/bin/srv.py +++ b/bin/srv.py @@ -27,7 +27,7 @@ app = Flask(__name__) MYDIR = os.path.abspath(os.path.dirname( os.path.dirname('__file__') )) sys.path.append("%s/lib/" % MYDIR) -from globals import LOG_FILE, TEMPLATES, STATIC, log, error +from globals import FILE_QUERIES_LOG, LOG_FILE, TEMPLATES, STATIC, log, error from cheat_wrapper import cheat_wrapper, save_cheatsheet @@ -47,6 +47,31 @@ def is_html_needed(user_agent): return False return True +def parse_args(args): + result = {} + + q = "" + for key, val in args.items(): + if len(val) == 0: + q += key + continue + + if q is None: + return result + if 'T' in q: + result['no-terminal'] = True + if 'q' in q: + result['quiet'] = True + + for key, val in args.items(): + if val == 'True': + val = True + if val == 'False': + val = False + result[key] = val + + return result + @app.route('/files/') def send_static(path): return send_from_directory(STATIC, path) @@ -59,6 +84,11 @@ def send_favicon(): def send_malformed(): return send_from_directory(STATIC, 'malformed-response.html') +def log_query(ip, found, topic, user_agent): + log_entry = "%s %s %s %s" % (ip, found, topic, user_agent) + with open(FILE_QUERIES_LOG, 'a') as my_file: + my_file.write(log_entry+"\n") + @app.route("/", methods=['GET', 'POST']) @app.route("/", methods=["GET", "POST"]) def answer(topic = None): @@ -76,6 +106,21 @@ def answer(topic = None): user_agent = request.headers.get('User-Agent', '').lower() html_needed = is_html_needed(user_agent) + options = parse_args(request.args) + + if request.headers.getlist("X-Forwarded-For"): + ip = request.headers.getlist("X-Forwarded-For")[0] + if ip.startswith('::ffff:'): + ip = ip[7:] + else: + ip = request.remote_addr + if request.headers.getlist("X-Forwarded-For"): + ip = request.headers.getlist("X-Forwarded-For")[0] + if ip.startswith('::ffff:'): + ip = ip[7:] + else: + ip = request.remote_addr + if request.method == 'POST': for k, v in request.form.items(): @@ -109,8 +154,9 @@ def answer(topic = None): if topic is None: topic = ":firstpage" - answer = cheat_wrapper(topic, html=is_html_needed(user_agent)) + answer, found = cheat_wrapper(topic, request_options=options, html=is_html_needed(user_agent)) + log_query(ip, found, topic, user_agent) return answer server = WSGIServer(("", 8002), app) # log=None) diff --git a/lib/cheat_wrapper.py b/lib/cheat_wrapper.py index 6eef153..83447e7 100644 --- a/lib/cheat_wrapper.py +++ b/lib/cheat_wrapper.py @@ -198,14 +198,26 @@ def split_paragraphs(text): return answer def paragraph_contains(paragraph, keyword, insensitive=False, word_boundaries=True): - regex = re.escape(keyword) - if not word_boundaries: - regex = r"\b%s\b" % keyword + """ + Several keywords can be joined together using ~ + For example: ~ssh~passphrase + """ + answer = True - if insensitive: - answer = bool(re.search(regex, paragraph, re.IGNORECASE)) + if '~' in keyword: + keywords = keyword.split('~') else: - answer = bool(re.search(regex, paragraph)) + keywords = [keyword] + + for keyword in keywords: + regex = re.escape(keyword) + if not word_boundaries: + regex = r"\b%s\b" % keyword + + if insensitive: + answer = answer and bool(re.search(regex, paragraph, re.IGNORECASE)) + else: + answer = answer and bool(re.search(regex, paragraph)) return answer @@ -322,9 +334,39 @@ def colorize_internal(topic, answer, html_needed): return answer +def github_button(topic_type): + repository = { + "cheat.sheets": 'chubin/cheat.sheets', + "cheat.sheets dir": 'chubin/cheat.sheets', + "tldr": 'tldr-pages/tldr', + "internal": '', + "cheat": 'chrisallenlane/cheat', + "search": '', + "internal": '', + "unknown": '', + } + + full_name = repository.get(topic_type, '') + if not full_name: + return '' + + short_name = full_name.split('/',1)[1] + button = ( + "" + '%(short_name)s' + ) % locals() + return button + # -def cheat_wrapper(query, highlight=True, html=False): +def cheat_wrapper(query, request_options=None, html=False): + + highlight = not bool(request_options and request_options.get('no-terminal')) keyword = None if '~' in query: @@ -346,6 +388,8 @@ def cheat_wrapper(query, highlight=True, html=False): search_mode = False + found = True # if the page was found in the database + editable = False # can generated page be edited on github (only cheat.sheets pages can) result = "" for topic, answer in answers: @@ -357,6 +401,9 @@ def cheat_wrapper(query, highlight=True, html=False): highlight = False topic_type = get_topic_type(topic) + if topic_type == 'unknown': + found = False + if highlight: if topic_type.endswith(" dir"): pass @@ -376,19 +423,29 @@ def cheat_wrapper(query, highlight=True, html=False): else: answer = pygments_highlight(answer, BashLexer(), Terminal256Formatter(style='native')) + if topic_type == "cheat.sheets": + editable = True + if search_mode: - result += "\n%s%s %s %s%s\n" % (colored.bg('dark_gray'), colored.attr("res_underlined"), topic, colored.attr("res_underlined"), colored.attr('reset')) + if highlight: + result += "\n%s%s %s %s%s\n" % (colored.bg('dark_gray'), colored.attr("res_underlined"), topic, colored.attr("res_underlined"), colored.attr('reset')) + else: + result += "[%s]" % topic result += answer if search_mode: result = result[1:] + editable = False + repository_button = '' + else: + repository_button = github_button(topic_type) if html: result = result + "\n$" result = html_wrapper(result) title = "cheat.sh/%s" % topic - title += '\n' + # title += '\nscript src="/files/awesomplete.min.js" async>' # submit button: thanks to http://stackoverflow.com/questions/477691/ submit_button = '' topic_list = """ @@ -397,10 +454,18 @@ def cheat_wrapper(query, highlight=True, html=False): """ % ("\n".join("" % x for x in get_topics_list())) curl_line = "$ curl cheat.sh/" - form_html = '
%s%s%s
' % (submit_button, curl_line, query, topic_list) - result = re.sub("
", form_html + "
", result)
+        if query == ':firstpage':
+            query = ""
+        form_html = '
%s%s%s
' % (submit_button, curl_line, query, topic_list) + + edit_button = '' + if editable: + edit_page_link = 'https://github.com/chubin/cheat.sheets/edit/master/sheets/' + topic + edit_button = '
[edit]
' % edit_page_link + result = re.sub("
", edit_button + form_html + "
", result)
         result = re.sub("", "" + title, result)
-        result = result.replace('', TWITTER_BUTTON + GITHUB_BUTTON + GITHUB_BUTTON_2 + GITHUB_BUTTON_FOOTER + '')
+        if not request_options.get('quiet'):
+            result = result.replace('', TWITTER_BUTTON + GITHUB_BUTTON + repository_button + GITHUB_BUTTON_FOOTER + '')
 
-    return result
+    return result, found
 
diff --git a/lib/globals.py b/lib/globals.py
index 998f770..9c29974 100644
--- a/lib/globals.py
+++ b/lib/globals.py
@@ -6,6 +6,7 @@ MYDIR = os.path.abspath(os.path.dirname( os.path.dirname('__file__') ))
 ANSI2HTML = os.path.join( MYDIR, "share/ansi2html.sh" )
 
 LOG_FILE  = os.path.join( MYDIR, 'log/main.log' )
+FILE_QUERIES_LOG  = os.path.join( MYDIR, 'log/queries.log' )
 TEMPLATES = os.path.join( MYDIR, 'share/templates' )
 STATIC    = os.path.join( MYDIR, 'share/static' )