示例#1
0
    def delete(self):
        cli = Client(remote, pull_token())
        try:
            r = cli.tokens_delete(request.data)

        except AuthError:
            return jsonify_unauth()

        except Exception as e:
            logger.error(e)
            return jsonify_unknown()

        return jsonify_success(r)
示例#2
0
    def delete(self):
        cli = Client(remote, pull_token())
        try:
            r = cli.tokens_delete(request.data)

        except AuthError:
            return jsonify_unauth()

        except Exception as e:
            logger.error(e)
            return jsonify_unknown()

        return jsonify_success(r)
示例#3
0
    def patch(self):
        cli = Client(remote, pull_token())
        try:
            r = cli.tokens_edit(request.data)

        except AuthError:
            return jsonify_unauth()

        except RuntimeError as e:
            return jsonify_unknown(msg=str(e))

        except Exception as e:
            logger.error(e)
            return jsonify_unknown()

        if not r:
            return jsonify_unauth()

        return jsonify_success(r)
示例#4
0
    def get(self):
        cli = Client(remote, pull_token())
        filters = {}

        for f in TOKEN_FILTERS:
            filters[f] = request.args.get(f)

        if current_app.config.get('dummy'):
            return jsonify_success()

        try:
            r = cli.tokens_search(filters)

        except AuthError:
            return jsonify_unauth()

        except Exception as e:
            logger.error(e)
            return jsonify_unknown()

        return jsonify_success(r)
示例#5
0
    def get(self):
        cli = Client(remote, pull_token())
        filters = {}

        for f in TOKEN_FILTERS:
            filters[f] = request.args.get(f)

        if current_app.config.get('dummy'):
            return jsonify_success()

        try:
            r = cli.tokens_search(filters)

        except AuthError:
            return jsonify_unauth()

        except Exception as e:
            logger.error(e)
            return jsonify_unknown()

        return jsonify_success(r)
示例#6
0
    def post(self):
        cli = Client(remote, pull_token())
        if not request.data:
            return jsonify_unknown('missing data', 400)

        if current_app.config.get('dummy'):
            return jsonify_success()

        try:
            r = cli.tokens_create(request.data)

        except AuthError:
            return jsonify_unauth()

        except Exception as e:
            logger.error(e)
            return jsonify_unknown()

        if not r:
            return jsonify_unknown('create failed', 400)

        return jsonify_success(r, code=201)
示例#7
0
    def post(self):
        cli = Client(remote, pull_token())
        if not request.data:
            return jsonify_unknown('missing data', 400)

        if current_app.config.get('dummy'):
            return jsonify_success()

        try:
            r = cli.tokens_create(request.data)

        except AuthError:
            return jsonify_unauth()

        except Exception as e:
            logger.error(e)
            return jsonify_unknown()

        if not r:
            return jsonify_unknown('create failed', 400)

        return jsonify_success(r, code=201)
示例#8
0
def login():
    if request.method == 'GET':
        return render_template('login.html')

    if request.method == 'POST':
        from cifsdk.client.zeromq import ZMQ as Client
        if request.form['token'] == '':
            return render_template('login.html')

        c = Client(remote, HTTPD_TOKEN)
        rv = c.tokens_search({'token': request.form['token']})
        if len(rv) == 0:
            return render_template('login.html', code=401)

        user = rv[0]

        if user['revoked']:
            return render_template('login.html', code=401)

        for e in ['username', 'token', 'admin', 'read', 'write', 'groups']:
            session[e] = user[e]

        return redirect(url_for('/u/search'))
示例#9
0
def tokens():
    cli = Client(remote, pull_token())
    if request.method == 'DELETE':
        try:
            r = cli.tokens_delete(request.data)
        except Exception as e:
            logger.error(e)
            response = jsonify({"message": "failed", "data": []})
            response.status_code = 503
        else:
            response = jsonify({'message': 'success', 'data': r})
            response.status_code = 200
    elif request.method == 'POST':
        if request.data:
            try:
                r = cli.tokens_create(request.data)
            except AuthError:
                response = jsonify({
                    'message': 'admin privs required',
                    'data': []
                })
                response.status_code = 401
            except Exception as e:
                logger.error(e)
                response = jsonify({'message': 'create failed', 'data': []})
                response.status_code = 503
            else:
                if r:
                    response = jsonify({'message': 'success', 'data': r})
                    response.status_code = 200
                else:
                    response = jsonify({
                        'message': 'admin privs required',
                        'data': []
                    })
                    response.status_code = 401
        else:
            response = jsonify({'message': 'create failed', 'data': []})
            response.status_code = 400
    elif request.method == 'PATCH':
        try:
            r = cli.tokens_edit(request.data)
        except AuthError:
            response = jsonify({'message': 'admin privs required', 'data': []})
            response.status_code = 401
        except Exception as e:
            logger.error(e)
            import traceback
            traceback.print_exc()
            response = jsonify({'message': 'create failed', 'data': []})
            response.status_code = 503
        else:
            if r:
                response = jsonify({'message': 'success', 'data': r})
                response.status_code = 200
            else:
                response = jsonify({
                    'message': 'admin privs required',
                    'data': []
                })
                response.status_code = 401
    else:
        filters = {}
        for f in TOKEN_FILTERS:
            filters[f] = request.args.get(f)

        try:
            r = cli.tokens_search(filters)
        except AuthError:
            response = jsonify({"message": "failed", "data": []})
            response.status_code = 401
        except Exception as e:
            logger.error(e)
            response = jsonify({"message": "failed", "data": []})
            response.status_code = 503
        else:
            response = jsonify({'message': 'success', 'data': r})
            response.status_code = 200

    return response
示例#10
0
def main():  # pragma: no cover
    p = get_argument_parser()
    p = ArgumentParser(description=textwrap.dedent('''\
        example usage:
            $ cif -q example.org -d
            $ cif --search 1.2.3.0/24
            $ cif --profile zeek
        '''),
                       formatter_class=RawDescriptionHelpFormatter,
                       prog='cif',
                       parents=[p])
    p.add_argument('--remote',
                   help='specify API remote [default %(default)s]',
                   default=REMOTE)
    p.add_argument('--no-verify-ssl', action='store_true')

    p.add_argument("--create", action="store_true", help="create an indicator")
    p.add_argument('--delete', action='store_true')
    p.add_argument('-q', '--search', help="search")

    p.add_argument('--itype', help='filter by indicator type')
    p.add_argument('--reported_at', help='specify reported_at filter')

    p.add_argument('-n',
                   '--nolog',
                   help='do not log search',
                   action='store_true')

    p.add_argument('-f',
                   '--format',
                   help='specify output format [default: %(default)s]"',
                   default=FORMAT,
                   choices=FORMATS.keys())

    p.add_argument('--indicator',
                   help='indicator (ip, url, etc..) '
                   'to search for')
    p.add_argument('--confidence', help="specify confidence level")
    p.add_argument('--tags', nargs='+', help='filter by tag(s)')
    p.add_argument('--provider', help='provider to filter by')
    p.add_argument('--asn', help='filter by asn')
    p.add_argument('--cc', help='filter by country code')
    p.add_argument('--asn-name', help='filter by asn name')
    p.add_argument('--rdata', help='filter by rdata')
    p.add_argument('--groups', help='filter by group(s)')

    p.add_argument('--days', help='filter results within last X days')
    p.add_argument('--today',
                   action='store_true',
                   help='auto-sets reported_at to today, 00:00:00Z (UTC)')

    p.add_argument('--limit',
                   help='limit results [default %(default)s]',
                   default=SEARCH_LIMIT)

    p.add_argument('--columns',
                   default=','.join(COLUMNS),
                   help='specify output columns [default %(default)s]')

    p.add_argument('--no-feed',
                   action='store_true',
                   help='return a non-filtered dataset (no whitelist applied)')

    p.add_argument('--profile',
                   help='specify feed profile',
                   choices=PROFILES.keys())

    args = p.parse_args()

    setup_logging(args)

    opts = vars(args)

    options = {}
    for k, v in opts.items():
        if v:
            options[k] = v

    if args.remote.startswith('http'):
        verify_ssl = True
        if args.no_verify_ssl:
            verify_ssl = False

        if args.remote == 'https://localhost':
            verify_ssl = False

        cli = Client(verify_ssl=verify_ssl)

    else:
        from cifsdk.client.zeromq import ZMQ
        cli = ZMQ()

    filters = {e: options.get(e) for e in VALID_FILTERS}

    if args.search:
        filters['indicator'] = args.search

    for k, v in filters.items():
        if v is True:
            filters[k] = 1

        if v is False:
            filters[k] = 0

    if options.get("create"):
        _create(cli, args, filters)
        raise SystemExit

    if options.get("delete"):
        _delete(cli, args, filters)
        raise SystemExit

    if not sys.stdin.isatty():
        buffer = sys.stdin.read().rstrip("\n").split("\n")

        filters = [{'indicator': i} for i in buffer]

    _search(cli, args, options, filters)
示例#11
0
def main():
    p = get_argument_parser()
    p = ArgumentParser(description=textwrap.dedent('''\
        example usage:
            $ cif -q example.org -d
            $ cif --search 1.2.3.0/24
            $ cif --ping
        '''),
                       formatter_class=RawDescriptionHelpFormatter,
                       prog='cif',
                       parents=[p])
    p.add_argument('--token', help='specify api token', default=TOKEN)
    p.add_argument('--remote',
                   help='specify API remote [default %(default)s]',
                   default=REMOTE_ADDR)
    p.add_argument('-p', '--ping', action="store_true")  # meg?
    p.add_argument('--ping-indef', action="store_true")
    p.add_argument('-q', '--search', help="search")
    p.add_argument('--itype', help='filter by indicator type'
                   )  ## need to fix sqlite for non-ascii stuff first
    p.add_argument("--submit", action="store_true", help="submit an indicator")
    p.add_argument('--limit',
                   help='limit results [default %(default)s]',
                   default=SEARCH_LIMIT)
    p.add_argument('--reporttime', help='specify reporttime filter')
    p.add_argument('-n',
                   '--nolog',
                   help='do not log search',
                   action='store_true')
    p.add_argument('-f',
                   '--format',
                   help='specify output format [default: %(default)s]"',
                   default=FORMAT,
                   choices=FORMATS.keys())

    p.add_argument('--indicator')
    p.add_argument('--tags', nargs='+')
    p.add_argument('--provider')
    p.add_argument('--confidence', help="specify confidence level")
    p.add_argument('--tlp', help="specify traffic light protocol")

    p.add_argument("--zmq",
                   help="use zmq as a transport instead of http",
                   action="store_true")

    p.add_argument('--config',
                   help='specify config file [default %(default)s]',
                   default=CONFIG_PATH)

    p.add_argument('--feed', action='store_true')

    p.add_argument('--no-verify-ssl', action='store_true')

    p.add_argument('--last-day',
                   action="store_true",
                   help='auto-sets reporttime to 23 hours and 59 seconds ago '
                   '(current time UTC) and reporttime-end to "now"')
    p.add_argument(
        '--last-hour',
        action='store_true',
        help='auto-sets reporttime to the beginning of the previous full'
        ' hour and reporttime-end to end of previous full hour')
    p.add_argument('--days', help='filter results within last X days')
    p.add_argument('--today',
                   help='auto-sets reporttime to today, 00:00:00Z (UTC)',
                   action='store_true')
    p.add_argument('--columns',
                   help='specify output columns [default %(default)s]',
                   default=','.join(COLUMNS))

    p.add_argument('--asn')
    p.add_argument('--cc')
    p.add_argument('--asn-desc')
    p.add_argument('--rdata')
    p.add_argument('--no-feed', action='store_true')
    p.add_argument('--region')
    p.add_argument('--groups', help='specify groups filter (csv)')

    p.add_argument('--delete', action='store_true')
    p.add_argument('--id')

    args = p.parse_args()

    setup_logging(args)
    logger = logging.getLogger(__name__)

    o = read_config(args)
    options = vars(args)
    for v in options:
        if v == 'remote' and options[v] == REMOTE_ADDR and o.get('remote'):
            options[v] = o['remote']
        if v == 'token' and o.get('token'):
            options[v] = o['token']
        if options[v] is None or options[v] == '':
            options[v] = o.get(v)

    if not options.get('token'):
        raise RuntimeError('missing --token')

    verify_ssl = True
    if o.get('no_verify_ssl') or options.get('no_verify_ssl'):
        verify_ssl = False

    if options.get("zmq"):
        from cifsdk.client.zeromq import ZMQ as ZMQClient
        cli = ZMQClient(**options)
    else:
        from cifsdk.client.http import HTTP as HTTPClient
        if args.remote == 'https://localhost':
            verify_ssl = False

        cli = HTTPClient(args.remote, args.token, verify_ssl=verify_ssl)

    if options.get('ping') or options.get('ping_indef'):
        logger.info('running ping')
        n = 4
        if args.ping_indef:
            n = 999

        try:
            for num in range(0, n):
                ret = cli.ping()
                if ret != 0:
                    print("roundtrip: {} ms".format(ret))
                    select.select([], [], [], 1)
                    from time import sleep
                    sleep(1)
                else:
                    logger.error('ping failed')
                    raise RuntimeError
        except KeyboardInterrupt:
            pass
        raise SystemExit

    if options.get("submit"):
        print("submitting {0}".format(options.get("submit")))
        i = Indicator(indicator=args.indicator,
                      tags=args.tags,
                      confidence=args.confidence,
                      group=args.groups,
                      tlp=args.tlp,
                      provider=args.provider)
        rv = cli.indicators_create(i)

        print('success id: {}\n'.format(rv))
        raise SystemExit

    filters = {
        'itype': options['itype'],
        'limit': options['limit'],
        'provider': options.get('provider'),
        'indicator': options.get('search') or options.get('indicator'),
        'nolog': options['nolog'],
        'tags': options['tags'],
        'confidence': options.get('confidence'),
        'asn': options.get('asn'),
        'asn_desc': options.get('asn_desc'),
        'cc': options.get('cc'),
        'region': options.get('region'),
        'rdata': options.get('rdata'),
        'reporttime': options.get('reporttime'),
        'groups': options.get('groups'),
        'tlp': options.get('tlp')
    }

    if args.last_day:
        filters['days'] = '1'
        del filters['reporttime']

    if args.last_hour:
        filters['hours'] = '1'
        del filters['reporttime']

    if args.days:
        filters['days'] = args.days
        del filters['reporttime']

    if args.today:
        now = arrow.utcnow()
        filters['reporttime'] = '{0}Z'.format(
            now.format('YYYY-MM-DDT00:00:00'))

    if filters.get('itype') and not filters.get('search') and not args.no_feed:
        logger.info('setting feed flag by default, use --no-feed to override')
        options['feed'] = True

    if options.get("delete"):
        if args.id:
            filters = {'id': args.id}

        filters = {f: filters[f] for f in filters if filters.get(f)}
        print("deleting {0}".format(filters))
        rv = cli.indicators_delete(filters)

        print('deleted: {}'.format(rv))
        raise SystemExit

    if options.get('feed'):
        if not filters.get('itype') and not ADVANCED:
            print('\nmissing --itype\n\n')
            raise SystemExit

        if not filters.get('tags') and not ADVANCED:
            print(
                '\nmissing --tags [phishing|malware|botnet|scanner|pdns|whitelist|...]\n\n'
            )
            raise SystemExit

        if not filters.get('confidence'):
            filters['confidence'] = 8

        if args.limit == SEARCH_LIMIT:
            filters['limit'] = FEED_LIMIT

        try:
            rv = cli.feed(filters=filters)

        except AuthError as e:
            logger.error('unauthorized')

        except KeyboardInterrupt:
            pass

        except Exception as e:
            logger.error(e)

        else:
            print(FORMATS[options.get('format')](data=rv,
                                                 cols=args.columns.split(',')))

        raise SystemExit

    try:
        rv = cli.search(filters)

    except AuthError as e:
        logger.error('unauthorized')

    except KeyboardInterrupt:
        pass

    except Exception as e:
        import traceback
        traceback.print_exc()
        logger.error(e)

    else:
        print(FORMATS[options.get('format')](data=rv,
                                             cols=args.columns.split(',')))
示例#12
0
def tokens():
    cli = Client(remote, pull_token())
    if request.method == 'DELETE':
        try:
            r = cli.tokens_delete(request.data)
        except Exception as e:
            logger.error(e)
            response = jsonify({
                "message": "failed",
                "data": []
            })
            response.status_code = 503
        else:
            response = jsonify({
                'message': 'success',
                'data': r
            })
            response.status_code = 200
    elif request.method == 'POST':
        if request.data:
            try:
                r = cli.tokens_create(request.data)
            except AuthError:
                response = jsonify({
                    'message': 'admin privs required',
                    'data': []
                })
                response.status_code = 401
            except Exception as e:
                logger.error(e)
                response = jsonify({
                    'message': 'create failed',
                    'data': []
                })
                response.status_code = 503
            else:
                if r:
                    response = jsonify({
                        'message': 'success',
                        'data': r
                    })
                    response.status_code = 200
                else:
                    response = jsonify({
                        'message': 'admin privs required',
                        'data': []
                    })
                    response.status_code = 401
        else:
            response = jsonify({
                'message': 'create failed',
                'data': []
            })
            response.status_code = 400
    elif request.method == 'PATCH':
        try:
            r = cli.tokens_edit(request.data)
        except AuthError:
            response = jsonify({
                'message': 'admin privs required',
                'data': []
            })
            response.status_code = 401
        except Exception as e:
            logger.error(e)
            import traceback
            traceback.print_exc()
            response = jsonify({
                'message': 'create failed',
                'data': []
            })
            response.status_code = 503
        else:
            if r:
                response = jsonify({
                    'message': 'success',
                    'data': r
                })
                response.status_code = 200
            else:
                response = jsonify({
                    'message': 'admin privs required',
                    'data': []
                })
                response.status_code = 401
    else:
        filters = {}
        for f in TOKEN_FILTERS:
            filters[f] = request.args.get(f)

        try:
            r = cli.tokens_search(filters)
        except AuthError:
            response = jsonify({
                "message": "failed",
                "data": []
            })
            response.status_code = 401
        except Exception as e:
            logger.error(e)
            response = jsonify({
                "message": "failed",
                "data": []
            })
            response.status_code = 503
        else:
            response = jsonify({
                'message': 'success',
                'data': r
            })
            response.status_code = 200

    return response
示例#13
0
def main():
    p = get_argument_parser()
    p = ArgumentParser(description=textwrap.dedent('''\
        example usage:
            $ cif -q example.org -d
            $ cif --search 1.2.3.0/24
            $ cif --ping
        '''),
                       formatter_class=RawDescriptionHelpFormatter,
                       prog='cif',
                       parents=[p])
    p.add_argument('--token', help='specify api token', default=TOKEN)
    p.add_argument('--remote',
                   help='specify API remote [default %(default)s]',
                   default=REMOTE_ADDR)
    p.add_argument('-p', '--ping', action="store_true")  # meg?
    p.add_argument('-q', '--search', help="search")
    p.add_argument('--itype', help='filter by indicator type'
                   )  ## need to fix sqlite for non-ascii stuff first
    p.add_argument("--submit", action="store_true", help="submit an indicator")
    p.add_argument('--limit',
                   help='limit results [default %(default)s]',
                   default=SEARCH_LIMIT)
    p.add_argument('--reporttime', help='specify reporttime filter')
    p.add_argument('-n',
                   '--nolog',
                   help='do not log search',
                   action='store_true')
    p.add_argument('-f',
                   '--format',
                   help='specify output format [default: %(default)s]"',
                   default=FORMAT,
                   choices=FORMATS.keys())

    p.add_argument('--indicator')
    p.add_argument('--tags', nargs='+')
    p.add_argument('--provider')
    p.add_argument('--confidence', help="specify confidence level")

    p.add_argument("--zmq",
                   help="use zmq as a transport instead of http",
                   action="store_true")

    p.add_argument('--config',
                   help='specify config file [default %(default)s]',
                   default=CONFIG_PATH)

    p.add_argument('--feed', action='store_true')

    p.add_argument('--no-verify-ssl', action='store_true')

    p.add_argument('--last-day',
                   action="store_true",
                   help='auto-sets reporttime to 23 hours and 59 seconds ago '
                   '(current time UTC) and reporttime-end to "now"')
    p.add_argument(
        '--last-hour',
        action='store_true',
        help='auto-sets reporttime to the beginning of the previous full'
        ' hour and reporttime-end to end of previous full hour')
    p.add_argument('--days', help='filter results within last X days')
    p.add_argument('--today',
                   help='auto-sets reporttime to today, 00:00:00Z (UTC)',
                   action='store_true')

    args = p.parse_args()

    setup_logging(args)
    logger = logging.getLogger(__name__)

    o = read_config(args)
    options = vars(args)
    for v in options:
        if v == 'remote' and options[v] == REMOTE_ADDR and o.get('remote'):
            options[v] = o['remote']
        if options[v] is None:
            options[v] = o.get(v)

    if not options.get('token'):
        raise RuntimeError('missing --token')

    verify_ssl = True
    if o.get('no_verify_ssl') or options.get('no_verify_ssl'):
        verify_ssl = False

    if options.get("zmq"):
        from cifsdk.client.zeromq import ZMQ as ZMQClient
        cli = ZMQClient(**options)
    else:
        from cifsdk.client.http import HTTP as HTTPClient
        if args.remote == 'https://localhost':
            verify_ssl = False

        cli = HTTPClient(args.remote, args.token, verify_ssl=verify_ssl)

    if options.get('ping'):
        logger.info('running ping')
        for num in range(0, 4):
            ret = cli.ping()
            if ret != 0:
                print("roundtrip: {} ms".format(ret))
                select.select([], [], [], 1)
            else:
                logger.error('ping failed')
                raise RuntimeError
        raise SystemExit

    if options.get("submit"):
        logger.info("submitting {0}".format(options.get("submit")))
        i = Indicator(indicator=args.indicator,
                      tags=args.tags,
                      confidence=args.confidence)
        rv = cli.indicators_create(i)

        logger.info('success id: {}'.format(rv))
        raise SystemExit

    filters = {
        'itype': options['itype'],
        'limit': options['limit'],
        'provider': options.get('provider'),
        'indicator': options.get('search'),
        'nolog': options['nolog'],
        'tags': options['tags'],
        'confidence': options.get('confidence')
    }

    if args.last_day:
        filters['days'] = '1'

    if args.last_hour:
        filters['hours'] = '1'

    if args.days:
        filters['days'] = args.days

    if args.today:
        now = arrow.utcnow()
        filters['reporttime'] = '{0}Z'.format(
            now.format('YYYY-MM-DDT00:00:00'))

    if options.get('feed'):
        if not filters.get('confidence'):
            filters['confidence'] = 8

        if not filters.get('reporttime') and not filters.get(
                'day') and not filters.get('hour'):
            filters['days'] = FEED_DAYS_LIMIT

        if args.limit == SEARCH_LIMIT:
            filters['limit'] = FEED_LIMIT

        try:
            rv = cli.feed(filters=filters)
        except AuthError as e:
            logger.error('unauthorized')
        else:
            print(FORMATS[options.get('format')](data=rv))

        raise SystemExit

    try:
        rv = cli.search(filters)
    except AuthError as e:
        logger.error('unauthorized')
    else:
        print(FORMATS[options.get('format')](data=rv))
def main():
    p = get_argument_parser()
    p = ArgumentParser(
        description=textwrap.dedent('''\
        example usage:
            $ cif -q example.org -d
            $ cif --search 1.2.3.0/24
            $ cif --ping
        '''),
        formatter_class=RawDescriptionHelpFormatter,
        prog='cif',
        parents=[p]
    )
    p.add_argument('--token', help='specify api token', default=TOKEN)
    p.add_argument('--remote', help='specify API remote [default %(default)s]', default=REMOTE_ADDR)
    p.add_argument('-p', '--ping', action="store_true")  # meg?
    p.add_argument('--ping-indef', action="store_true")
    p.add_argument('-q', '--search', help="search")
    p.add_argument('--itype', help='filter by indicator type')  ## need to fix sqlite for non-ascii stuff first
    p.add_argument("--submit", action="store_true", help="submit an indicator")
    p.add_argument('--limit', help='limit results [default %(default)s]', default=SEARCH_LIMIT)
    p.add_argument('--reporttime', help='specify reporttime filter')
    p.add_argument('-n', '--nolog', help='do not log search', action='store_true')
    p.add_argument('-f', '--format', help='specify output format [default: %(default)s]"', default=FORMAT, choices=FORMATS.keys())

    p.add_argument('--indicator')
    p.add_argument('--tags', nargs='+')
    p.add_argument('--provider')
    p.add_argument('--confidence', help="specify confidence level")
    p.add_argument('--tlp', help="specify traffic light protocol")

    p.add_argument("--zmq", help="use zmq as a transport instead of http", action="store_true")

    p.add_argument('--config', help='specify config file [default %(default)s]', default=CONFIG_PATH)

    p.add_argument('--feed', action='store_true')

    p.add_argument('--no-verify-ssl', action='store_true')

    p.add_argument('--last-day', action="store_true", help='auto-sets reporttime to 23 hours and 59 seconds ago '
                                                           '(current time UTC) and reporttime-end to "now"')
    p.add_argument('--last-hour', action='store_true', help='auto-sets reporttime to the beginning of the previous full'
                                                            ' hour and reporttime-end to end of previous full hour')
    p.add_argument('--days', help='filter results within last X days')
    p.add_argument('--today', help='auto-sets reporttime to today, 00:00:00Z (UTC)', action='store_true')
    p.add_argument('--columns', help='specify output columns [default %(default)s]', default=','.join(COLUMNS))
    p.add_argument('--fields', help='same as --columns [default %(default)s]', default=','.join(COLUMNS))

    p.add_argument('--asn')
    p.add_argument('--cc')
    p.add_argument('--asn-desc')
    p.add_argument('--rdata')
    p.add_argument('--no-feed', action='store_true')
    p.add_argument('--region')
    p.add_argument('--groups', help='specify groups filter (csv)')

    p.add_argument('--delete', action='store_true')
    p.add_argument('--id')

    args = p.parse_args()

    if args.fields != ','.join(COLUMNS):
        args.columns = args.fields

    setup_logging(args)
    logger = logging.getLogger(__name__)

    o = read_config(args)
    options = vars(args)

    # support for separate read and write tokens
    if o.get('write_token') and options.get('submit'):
	    o['token'] = o['write_token']
    elif o.get('read_token'):
        o['token'] = o['read_token']

    for v in options:
        if v == 'remote' and options[v] == REMOTE_ADDR and o.get('remote'):
            options[v] = o['remote']
        if v == 'token' and o.get('token'):
            options[v] = o['token']
        if options[v] is None or options[v] == '':
            options[v] = o.get(v)

    if not options.get('token'):
        raise RuntimeError('missing --token')

    verify_ssl = True
    if o.get('no_verify_ssl') or options.get('no_verify_ssl'):
        verify_ssl = False

    if options.get("zmq"):
        from cifsdk.client.zeromq import ZMQ as ZMQClient
        cli = ZMQClient(**options)
    else:
        from cifsdk.client.http import HTTP as HTTPClient
        if args.remote == 'https://localhost':
            verify_ssl = False

        cli = HTTPClient(args.remote, args.token, verify_ssl=verify_ssl)

    if options.get('ping') or options.get('ping_indef'):
        logger.info('running ping')
        n = 4
        if args.ping_indef:
            n = 999

        try:
            for num in range(0, n):
                ret = cli.ping()
                if ret != 0:
                    print("roundtrip: {} ms".format(ret))
                    select.select([], [], [], 1)
                    from time import sleep
                    sleep(1)
                else:
                    logger.error('ping failed')
                    raise RuntimeError
        except KeyboardInterrupt:
            pass
        raise SystemExit

    if options.get("submit"):
        print("submitting {0}".format(options.get("submit")))
        i = Indicator(indicator=args.indicator, tags=args.tags, confidence=args.confidence, group=args.groups, tlp=args.tlp, provider=args.provider)
        rv = cli.indicators_create(i)

        print('success id: {}\n'.format(rv))
        raise SystemExit

    filters = {
        'itype': options['itype'],
        'limit': options['limit'],
        'provider': options.get('provider'),
        'indicator': options.get('search') or options.get('indicator'),
        'nolog': options['nolog'],
        'tags': options['tags'],
        'confidence': options.get('confidence'),
        'asn': options.get('asn'),
        'asn_desc': options.get('asn_desc'),
        'cc': options.get('cc'),
        'region': options.get('region'),
        'rdata': options.get('rdata'),
        'reporttime': options.get('reporttime'),
        'groups': options.get('groups'),
        'tlp': options.get('tlp')
    }

    if args.last_day:
        filters['days'] = '1'
        del filters['reporttime']

    if args.last_hour:
        filters['hours'] = '1'
        del filters['reporttime']

    if args.days:
        filters['days'] = args.days
        del filters['reporttime']

    if args.today:
        now = arrow.utcnow()
        filters['reporttime'] = '{0}Z'.format(now.format('YYYY-MM-DDT00:00:00'))

    if filters.get('itype') and not filters.get('search') and not args.no_feed:
        logger.info('setting feed flag by default, use --no-feed to override')
        options['feed'] = True

    if options.get("delete"):
        if args.id:
            filters = {'id': args.id}

        filters = {f: filters[f] for f in filters if filters.get(f)}
        print("deleting {0}".format(filters))
        rv = cli.indicators_delete(filters)

        print('deleted: {}'.format(rv))
        raise SystemExit

    if options.get('feed'):
        if not filters.get('itype') and not ADVANCED:
            print('\nmissing --itype\n\n')
            raise SystemExit

        if not filters.get('tags') and not ADVANCED:
            print('\nmissing --tags [phishing|malware|botnet|scanner|pdns|whitelist|...]\n\n')
            raise SystemExit

        if not filters.get('confidence'):
            filters['confidence'] = 8

        if args.limit == SEARCH_LIMIT:
            filters['limit'] = FEED_LIMIT

        try:
            rv = cli.feed(filters=filters)

        except AuthError as e:
            logger.error('unauthorized')

        except KeyboardInterrupt:
            pass

        except Exception as e:
            logger.error(e)

        else:
            print(FORMATS[options.get('format')](data=rv, cols=args.columns.split(',')))

        raise SystemExit

    try:
        rv = cli.search(filters)

    except AuthError as e:
        logger.error('unauthorized')

    except KeyboardInterrupt:
        pass

    except Exception as e:
        import traceback
        traceback.print_exc()
        logger.error(e)

    else:
        print(FORMATS[options.get('format')](data=rv, cols=args.columns.split(',')))
def main():
    p = get_argument_parser()
    p = ArgumentParser(
        description=textwrap.dedent('''\
        example usage:
            $ cif -q example.org -d
            $ cif --search 1.2.3.0/24
            $ cif --ping
        '''),
        formatter_class=RawDescriptionHelpFormatter,
        prog='cif',
        parents=[p]
    )
    p.add_argument('--token', help='specify api token', default=TOKEN)
    p.add_argument('--remote', help='specify API remote [default %(default)s]', default=REMOTE_ADDR)
    p.add_argument('-p', '--ping', action="store_true") # meg?
    p.add_argument('-q', '--search', help="search")
    p.add_argument('--itype', help='filter by indicator type')  ## need to fix sqlite for non-ascii stuff first
    p.add_argument("--submit", action="store_true", help="submit an indicator")
    p.add_argument('--limit', help='limit results [default %(default)s]', default=SEARCH_LIMIT)
    p.add_argument('-n', '--nolog', help='do not log search', action='store_true')
    p.add_argument('-f', '--format', help='specify output format [default: %(default)s]"', default=FORMAT, choices=FORMATS.keys())

    p.add_argument('--indicator')
    p.add_argument('--tags', nargs='+')
    p.add_argument('--provider')

    p.add_argument("--zmq", help="use zmq as a transport instead of http", action="store_true")

    p.add_argument('--config', help='specify config file [default %(default)s]', default=CONFIG_PATH)

    args = p.parse_args()

    setup_logging(args)
    logger = logging.getLogger(__name__)

    o = read_config(args)
    options = vars(args)
    for v in options:
        if options[v] is None:
            options[v] = o.get(v)

    if not options.get('token'):
        raise RuntimeError('missing --token')

    verify_ssl = True
    if o.get('no_verify_ssl') or options.get('no_verify_ssl'):
        verify_ssl = False

    options = vars(args)

    if options.get("zmq"):
        from cifsdk.client.zeromq import ZMQ as ZMQClient
        cli = ZMQClient(**options)
    else:
        from cifsdk.client.http import HTTP as HTTPClient
        cli = HTTPClient(args.remote, args.token, verify_ssl=verify_ssl)

    if options.get('ping'):
        logger.info('running ping')
        for num in range(0, 4):
            ret = cli.ping()
            if ret != 0:
                print("roundtrip: {} ms".format(ret))
                select.select([], [], [], 1)
            else:
                logger.error('ping failed')
                raise RuntimeError
    elif options.get('itype'):
        logger.info('searching for {}'.format(options['itype']))
        try:
            rv = cli.search({
                'itype': options['itype'],
                'limit': options['limit'],
                'provider': options.get('provider')
            })
        except AuthError as e:
            logger.error('unauthorized')
        except RuntimeError as e:
            import traceback
            traceback.print_exc()
            logger.error(e)
        else:
            print(FORMATS[options.get('format')](data=rv))
    elif options.get('search'):
        logger.info("searching for {0}".format(options.get("search")))
        try:
            rv = cli.indicators_search({
                    'indicator': options['search'],
                    'limit': options['limit'],
                    'nolog': options['nolog']
                }
            )
        except RuntimeError as e:
            import traceback
            traceback.print_exc()
            logger.error(e)
        except AuthError as e:
            logger.error('unauthorized')
        else:
            print(FORMATS[options.get('format')](data=rv))
    elif options.get("submit"):
        logger.info("submitting {0}".format(options.get("submit")))

        rv = cli.submit(indicator=args.indicator, tags=args.tags)