Skip to content

Commit

Permalink
Merge pull request #32 from alichtman/aarondev
Browse files Browse the repository at this point in the history
Click CLI added
  • Loading branch information
alichtman authored Apr 6, 2018
2 parents e0755f6 + 4cf80f4 commit 3b5a310
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 34 deletions.
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# stronghold

<!-- TODO: Get high quality static images -->
<!-- [![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/alichtman/stronghold/blob/master/LICENSE)
<!--
[![build](https://img.shields.io/wercker/ci/wercker/docs.svg)]() -->
<!-- ![Made With Python](img/made-with-python.png) -->
<!-- ![python versions](img/python-versions.png) -->
<!-- ![license](img/mit-license.png) -->
<!-- ![PRs Welcome](img/PRs-welcome.png) -->

<!-- Add Travis CI -->
<!-- [![Build Status](https://travis-ci.org/bevacqua/awesome-badges.svg?branch=master)](https://travis-ci.org/bevacqua/awesome-badges) -->

[![asciicast demo](https://asciinema.org/a/xQu2INqyjy4mK4k5aPRCMy0rJ.png)](https://asciinema.org/a/xQu2INqyjy4mK4k5aPRCMy0rJ?speed=1.75)
[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/alichtman/stronghold/blob/master/LICENSE)
![status](https://img.shields.io/pypi/status/Django.svg)

`stronghold` is the easiest way to securely configure your Mac.

![GIF demo](img/demo.gif)

Designed for MacOS Sierra and High Sierra.
Previously `fortify`.

Expand All @@ -27,10 +27,19 @@ Previously `fortify`.
* [python-macadmin-tools](https://github.com/timsutton/python-macadmin-tools)
* [tools-osx](https://github.com/morgant/tools-osx)

**Warnings**
**Usage**
---

+ Ensure you have up-to-date backups. This script modifies system settings and there is always a possibility that it will damage your system.
```
Usage: stronghold [-lockdown] [-v] [-h]
Securely configure your Mac from the terminal.
Options:
-lockdown Set secure configuration without user interaction.
-v Display version and author information and exit.
-help, -h Show this message and exit.
```

**Installation Options**
---
Expand Down
2 changes: 1 addition & 1 deletion constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class Constants:
PROJECT_NAME='stronghold'
VERSION='1.1.0'
VERSION='1.1.1'
AUTHOR_GITHUB='alichtman'
AUTHOR_FULL_NAME='Aaron Lichtman'
PUBLISHED="04/02/2018"
Expand Down
Binary file removed img/PRs-welcome.png
Binary file not shown.
Binary file added img/demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed img/made-with-python.png
Binary file not shown.
Binary file removed img/python-versions.png
Binary file not shown.
26 changes: 19 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,22 @@
# argument as follows, which will expect a file called
# `stronghold.py` to exist:
#
py_modules=["stronghold", "constants"],
py_modules=[
"stronghold",
"constants"
],

# This field lists other packages that your project depends on to run.
# Any package you put here will be installed by pip when your project is
# installed, so they must be valid existing projects.
#
# For an analysis of "install_requires" vs pip's requirements files see:
# https://packaging.python.org/en/latest/requirements.html
install_requires=['colorama == 0.3.9', 'inquirer == 2.2.0'],
install_requires=[
'colorama>=0.3.9',
'inquirer>=2.2.0',
'Click'
],

# To provide executable scripts, use entry points in preference to the
# "scripts" keyword. Entry points provide cross-platform support and allow
Expand All @@ -111,11 +118,16 @@
#
# For example, the following would provide a command called `sample` which
# executes the function `main` from this package when invoked:
entry_points={
'console_scripts': [
'stronghold=stronghold:main',
],
},
entry_points='''
[console_scripts]
stronghold=stronghold:cli
''',

# entry_points={
# 'console_scripts': [
# 'stronghold=stronghold:main',
# ],
# },

# List additional URLs that are relevant to your project as a dict.
#
Expand Down
108 changes: 89 additions & 19 deletions stronghold.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@

# Built-in modules
import sys
import argparse
import subprocess as sp
from time import sleep

# 3rd party modules
import click
import inquirer
from colorama import Fore, Style

# Local modules
from constants import Constants


def prompt_yes_no(top_line="", bottom_line="",):
"""Print question and return True or False depending on user selection from list.
bottom_line should be used for one liners. Otherwise, it's the second line you want printed.
Expand Down Expand Up @@ -45,14 +46,14 @@ def prompt_yes_no(top_line="", bottom_line="",):
def print_section_header(title, COLOR):
"""Prints variable sized section header"""
block = "#" * (len(title) + 2)
print("\n" + COLOR + Style.BRIGHT + block)
print(COLOR + Style.BRIGHT + block)
print("#", title)
print(block + "\n" + Style.RESET_ALL)


def print_confirmation(action):
"""Prints confirmation of action in bright yellow."""
print(Fore.YELLOW + Style.BRIGHT + action + Style.RESET_ALL)
print(Fore.YELLOW + Style.BRIGHT + action + Style.RESET_ALL + "\n")


def print_abort(config_type):
Expand Down Expand Up @@ -94,6 +95,8 @@ def splash_intro():
def firewall_config():
"""Firewall configuration options."""

print_section_header("FIREWALL", Fore.BLUE)

if prompt_yes_no(top_line = "-> Turn on firewall?",
bottom_line = "This helps protect your Mac from being attacked over the internet."):

Expand Down Expand Up @@ -134,6 +137,8 @@ def firewall_config():
def captive_portal_config():
"""Captive Portal configuration options."""

print_section_header("CAPTIVE PORTAL", Fore.BLUE)

if prompt_yes_no(top_line = "-> Disable Captive Portal Assistant and force login through browser on untrusted networks?",
bottom_line = "Captive Portal could be triggered and direct you to a malicious site WITHOUT any user interaction."):
print_confirmation("Disabling Captive Portal Assistant...")
Expand All @@ -144,6 +149,8 @@ def captive_portal_config():
def user_metadata_config():
"""User metadata configuration options."""

print_section_header("USER METADATA", Fore.BLUE)

###
# Language Modeling Data
###
Expand Down Expand Up @@ -199,6 +206,8 @@ def user_metadata_config():
def user_safety_config():
"""User Safety configuration options."""

print_section_header("USER SAFETY", Fore.BLUE)

if prompt_yes_no(top_line = "-> Lock Mac as soon as screen saver starts?",
bottom_line = "If your screen is black or on screensaver mode, you'll be prompted for a password to login every time."):
print_confirmation("Configuring account lock on screensaver...")
Expand Down Expand Up @@ -227,6 +236,8 @@ def user_safety_config():

def final_configuration():

print_section_header("FINAL CONFIGURATION STEPS", Fore.BLUE)

if prompt_yes_no(top_line = "-> Restart your Mac right now?",
bottom_line = "This is necessary for some configuration changes to take effect."):
print_confirmation("Configuration complete after restart!\n")
Expand All @@ -242,34 +253,93 @@ def final_configuration():
sleep(1)
if sp.run(['sudo', 'shutdown', '-r', 'now'], shell=True, stdout=sp.PIPE) != 0:
print(Fore.RED + Style.BRIGHT + "WARNING: Configuration not complete! A full restart is necessary.")
sys.exit()

else:
print(Fore.RED + Style.BRIGHT + "WARNING: Configuration not complete! A full restart is necessary.")
sys.exit()


def main():
def lockdown_procedure():

# argument parsing
parser = argparse.ArgumentParser(prog=Constants.PROJECT_NAME, description=Constants.DESCRIPTION)
parser.add_argument('-version', '-v', '-info', action='version', version='%(prog)s {} by {} -> (Github: {})'.format(Constants.VERSION, Constants.AUTHOR_FULL_NAME, Constants.AUTHOR_GITHUB))
args = parser.parse_args()
print("----------")
print_section_header("LOCKDOWN", Fore.BLUE)
print_confirmation("Set secure configuration without user interaction.")

splash_intro()
# Get sudo priv
sp.run("sudo -E -v", shell=True, stdout=sp.PIPE)

print_section_header("FIREWALL", Fore.BLUE)
firewall_config()
####
# FIREWALL
####

print_section_header("CAPTIVE PORTAL", Fore.BLUE)
captive_portal_config()
sp.run(['sudo', 'launchctl', 'load', '/System/Library/LaunchDaemons/com.apple.alf.agent.plist'], stdout=sp.PIPE)
sp.run(['sudo', 'launchctl', 'load', '/System/Library/LaunchAgents/com.apple.alf.useragent.plist'], stdout=sp.PIPE)
sp.run(['sudo', '/usr/libexec/ApplicationFirewall/socketfilterfw', '--setglobalstate', 'on'], stdout=sp.PIPE)
sp.run(['sudo', '/usr/libexec/ApplicationFirewall/socketfilterfw', '--setloggingmode', 'on'], stdout=sp.PIPE)
sp.run(['sudo', '/usr/libexec/ApplicationFirewall/socketfilterfw', '--setstealthmode', 'on'], stdout=sp.PIPE)
sp.run(['sudo', '/usr/libexec/ApplicationFirewall/socketfilterfw', '--setallowsigned', 'off'], stdout=sp.PIPE)
sp.run(['sudo', '/usr/libexec/ApplicationFirewall/socketfilterfw', '--setallowsignedapp', 'off'], stdout=sp.PIPE)
sp.run(['sudo', 'pkill', '-HUP', 'socketfilterfw'], stdout=sp.PIPE)

print_section_header("USER METADATA", Fore.BLUE)
user_metadata_config()
####
# CAPTIVE PORTAL
####

print_section_header("USER SAFETY", Fore.BLUE)
user_safety_config()
sp.run(['sudo', 'defaults', 'write', '/Library/Preferences/SystemConfiguration/com.apple.captive.control', 'Active', '-bool', 'false'], stdout=sp.PIPE)

####
# USER METADATA
####

sp.run(['rm', '-rfv', '"~/Library/LanguageModeling/*"', '"~/Library/Spelling/*"', '"~/Library/Suggestions/*"']) #, stdout=sp.PIPE)
sp.run(['rm', '-rfv', '"~/Library/Application Support/Quick Look/*"'], stdout=sp.PIPE)
sp.run([':>~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2'], shell=True, stdout=sp.PIPE)

####
# USER SAFETY
####

sp.run(['defaults', 'write', 'com.apple.screensaver', 'askForPassword', '-int', '1'], stdout=sp.PIPE)
sp.run(['defaults', 'write', 'com.apple.screensaver', 'askForPasswordDelay', '-int', '0'], stdout=sp.PIPE)
sp.run(['defaults', 'write', 'NSGlobalDomain', 'AppleShowAllExtensions', '-bool', 'true'], stdout=sp.PIPE)
sp.run(['defaults', 'write', 'NSGlobalDomain', 'NSDocumentSaveNewDocumentsToCloud', '-bool', 'false'], stdout=sp.PIPE)
sp.run(['defaults', 'write', 'com.apple.finder', 'AppleShowAllFiles', '-boolean', 'true'], shell=True, stdout=sp.PIPE)
sp.run(['killAll', 'Finder'], stdout=sp.PIPE)

####
# RESTART
####

print_section_header("FINAL CONFIGURATION STEPS", Fore.BLUE)
final_configuration()

# Click custom help
CONTEXT_SETTINGS = dict(help_option_names=['-h', '-help'])

@click.command(context_settings=CONTEXT_SETTINGS)
@click.option('-lockdown', is_flag=True, default=False, help="Set secure configuration without user interaction.")
@click.option('-v', is_flag=True, default=False, help='Display version and author information and exit.')
def cli(lockdown, v):
"""Securely configure your Mac from the terminal."""

# Print version information
if v:
print('stronghold {} by {} -> (Github: {})'.format(Constants.VERSION, Constants.AUTHOR_FULL_NAME, Constants.AUTHOR_GITHUB))
sys.exit()

# Lockdown
if lockdown:
lockdown_procedure()

# interactive walkthrough
else:
splash_intro()
firewall_config()
captive_portal_config()
user_metadata_config()
user_safety_config()
final_configuration()


if __name__ == '__main__':
main()
cli()

0 comments on commit 3b5a310

Please sign in to comment.