예제 #1
0
    def visit_let_node(self, node: LetNode):
        for kv_node in node.assignments_node.kv_nodes:
            lhs_chain = []
            with self.consumer(lambda v: lhs_chain.append(v)):
                self._unwind_lhs(kv_node.key_node)

            rhs = Ref()
            with self.consumer(lambda v: rhs.set(v)):
                kv_node.value_node.accept(self)

            if len(lhs_chain) == 1:
                self.context[lhs_chain[0]] = rhs.get()
            else:
                if not lhs_chain[0] in self.context:
                    raise PeekError(f'Unknown name: {lhs_chain[0]!r}')
                lhs = self.context[lhs_chain[0]]
                for x in lhs_chain[1:-1]:
                    if isinstance(lhs, dict) or (isinstance(lhs, list)
                                                 and isinstance(x, int)):
                        lhs = lhs[x]
                    else:
                        raise PeekError(
                            f'Invalid lhs for assignment: {lhs_chain}')

                x = lhs_chain[-1]
                if isinstance(lhs, dict) or (isinstance(lhs, list)
                                             and isinstance(x, int)):
                    lhs[x] = rhs.get()
                else:
                    raise PeekError(f'Invalid lhs for assignment: {lhs_chain}')
예제 #2
0
 def current(self):
     if self._index_current is None:
         raise PeekError('No ES client is configured')
     if self._index_current < 0 or self._index_current >= len(
             self._clients):
         raise PeekError(
             f'Attempt to get ES client at invalid index [{self._index_current}]'
         )
     return self._clients[self._index_current]
예제 #3
0
 def move_current_to(self, idx: int):
     if not isinstance(idx, int):
         raise PeekError(f'Index must be integer, got {idx!r}')
     if 0 <= idx < len(self._clients):
         if idx == self._index_current:
             return
         self._clients.insert(idx, self._clients.pop(self._index_current))
         self._index_current = idx
     else:
         raise PeekError(
             f'Attempt to move ES client to an invalid index: {idx!r}')
예제 #4
0
def _connect_userpass(app, **options):
    username = options.get('username')
    password = options.get('password')
    if options['hosts']:
        service_name = f'peek/{options["hosts"]}/userpass'
    else:
        service_name = f'peek/{options["cloud_id"]}/userpass'

    if not username and password:
        raise PeekError('Username is required for userpass authentication')

    if options['force_prompt']:
        password = app.input(message='Please enter password: '******'PEEK_PASSWORD', None)
        if not password:
            if app.config.as_bool('use_keyring'):
                password = _keyring(service_name, username)
                if not password:
                    if options['no_prompt']:
                        raise PeekError(
                            'Password is not found and password prompt is disabled'
                        )
                    password = app.input(message='Please enter password: '******'no_prompt']:
                    raise PeekError(
                        'Password is not found and password prompt is disabled'
                    )
                password = app.input(message='Please enter password: '******'use_keyring'):
        _keyring(service_name, username, password)

    return EsClient(
        name=options['name'],
        hosts=options['hosts'],
        cloud_id=options['cloud_id'],
        username=username,
        password=password,
        use_ssl=options['use_ssl'],
        verify_certs=options['verify_certs'],
        assert_hostname=options['assert_hostname'],
        ca_certs=options['ca_certs'],
        client_cert=options['client_cert'],
        client_key=options['client_key'],
        headers=options['headers'],
    )
예제 #5
0
 def _unwind_lhs(self, node: Node):
     if isinstance(node, NameNode):
         self.consume(node.token.value)
     elif isinstance(node, BinOpNode):
         if node.op_token.value != '.':
             raise PeekError(
                 f'lhs can only have variable and dot notation, but got {node!r}'
             )
         self._unwind_lhs(node.left_node)
         node.right_node.accept(self)
     else:
         raise PeekError(
             f'lhs can only have variable and dot notation, but got {node!r}'
         )
예제 #6
0
파일: saml.py 프로젝트: ywangd/peek
def saml_authenticate(es_client: EsClient, realm: str, callback_port: str,
                      callback_ssl: bool, name: Optional[str]):
    _logger.info(
        f'SAML authenticate for realm {realm!r} and callback port {callback_port!r}'
    )
    prepare_response = _saml_prepare(es_client, realm)
    httpd = _saml_start_http_server(callback_port, callback_ssl)
    print('Please use browser to complete authentication against the idP')
    webbrowser.open(prepare_response['redirect'])
    callback_path = _SamlExchange.callback_path.get()
    if isinstance(callback_path, bytes):
        callback_path = callback_path.decode('utf-8')
    try:
        httpd.shutdown()
        query = urllib.parse.parse_qs(callback_path)
        if 'SAMLResponse' not in query or len(query['SAMLResponse']) != 1:
            raise PeekError(
                f'Invalid saml callback response: {callback_path!r}')
        content = query['SAMLResponse'][0]
        auth_response = _saml_do_authenticate(es_client, realm,
                                              prepare_response['id'], content)
        return RefreshingEsClient(es_client,
                                  auth_response['username'],
                                  auth_response['access_token'],
                                  auth_response['refresh_token'],
                                  auth_response['expires_in'],
                                  name=name)
    finally:
        _SamlExchange.callback_path = None
예제 #7
0
def krb_authenticate(es_client: EsClient, service=None, username=None, name=None):
    _logger.debug(f'Connection with Kerberos: {service}')
    if service is None:
        raise PeekError('Service is required for kerberos authentication')
    import kerberos
    result, context = kerberos.authGSSClientInit(service, principal=username)
    kerberos.authGSSClientStep(context, '')
    ticket = kerberos.authGSSClientResponse(context)
    _logger.debug(f'Kerberos ticket: {ticket}')
    auth_response = es_client.perform_request(
        'POST',
        '/_security/oauth2/token',
        json.dumps({
            'grant_type': '_kerberos',
            'kerberos_ticket': ticket,
        }),
        deserialize_it=True)
    _logger.debug(f'Kerberos Token auth response: {auth_response}')

    return RefreshingEsClient(
        es_client,
        '_KRB',
        auth_response['access_token'],
        auth_response['refresh_token'],
        auth_response['expires_in'],
        name=name)
예제 #8
0
 def remove_client(self, x=None):
     if x is None:
         self.remove_client(self._index_current)
     elif isinstance(x, str):
         idx = self._clients.index(self.get_client(x))
         self.remove_client(idx)
     elif isinstance(x, int):
         if x < 0 or x >= len(self._clients):
             raise PeekError(
                 f'Attempt to remove ES client at invalid index [{x}]')
         removed = self._clients.pop(x)
         if not self._clients:
             self._index_current = None
             return
         if x < self._index_current:
             self._index_current -= 1
         elif x == self._index_current:
             self._index_current = 0
         for listener in self.listeners:
             if listener.on_remove(self, removed) is False:
                 break
     else:
         raise ValueError(
             f'Connection must be specified by either name or index, got {x!r}'
         )
예제 #9
0
def dot(left_operand, right_operand):
    if isinstance(left_operand, dict):
        if right_operand in left_operand:
            return left_operand[right_operand]
        else:
            raise PeekError(
                f'Value {left_operand!r} does not have key {right_operand!r}')
    elif isinstance(left_operand, list):
        if isinstance(right_operand, int):
            return left_operand[right_operand]
        else:
            raise PeekError(
                f'Cannot index array {left_operand!r} with non-integer value: {right_operand!r}'
            )
    else:
        raise PeekError(
            f'Value {left_operand!r} must be either an array or dict')
예제 #10
0
    def visit_unary_op_node(self, node: UnaryOpNode):
        operand = Ref()
        with self.consumer(lambda v: operand.set(v)):
            node.operand_node.accept(self)

        op_func = self._unary_op_funcs.get(node.op_token.value, None)
        if op_func is None:
            raise PeekError(f'Unknown unary operator: {node.op_token.value!r}')
        self.consume(op_func(operand.get()))
예제 #11
0
파일: peekapp.py 프로젝트: ywangd/peek
    def start_capture(self, f=None):
        if not isinstance(self.capture, NoOpCapture):
            raise PeekError(
                f'Cannot capture when one is currently running: {self.capture.status()}'
            )

        if f is None:
            f = f'{datetime.now().strftime("%Y%m%d%H%M%S")}.es'
        self.capture = FileCapture(f)
        return self.capture.status()
예제 #12
0
def consolidate_options(options, defaults):
    """
    Merge shorthanded @symbol into normal options kv pair with provided defaults
    """
    final_options = {k: v for k, v in options.items() if k != '@'}
    for symbol in options.get('@', []):
        if symbol not in defaults:
            raise PeekError(f'Unknown shorthanded flag: {symbol}')
        final_options[symbol] = defaults[symbol]
    return final_options
예제 #13
0
    def __call__(self, app, func=None, **options):
        if func is None:
            return '\n'.join(k for k in app.vm.functions.keys())

        for k, v in app.vm.functions.items():
            if v == func:
                description = getattr(v, "description", None)
                header = k + (f' - {description}' if description else '')
                return f'{header}\n{getattr(func, "options", {})}'
        else:
            raise PeekError(f'No such function: {func}')
예제 #14
0
 def __call__(self, app, index=None, **options):
     if index is None:
         history = []
         for entry in app.history.load_recent(
                 size=options.get('size', 100)):
             history.append(f'{entry[0]:>6} {entry[1]!r}')
         return '\n'.join(history)
     else:
         entry = app.history.get_entry(index)
         if entry is None:
             raise PeekError(f'History not found for index: {index}')
         app.process_input(entry[1])
예제 #15
0
    def __call__(self, app, **options):
        options = consolidate_options(options, {
            'load': DEFAULT_SAVE_NAME,
            'save': DEFAULT_SAVE_NAME,
            'clear': None,
        })

        if not options:
            return app.history.list_sessions()

        if 'load' in options:
            load = options.get('load')
            data = app.history.load_session(load)
            if data is None:
                raise PeekError(f'Session not found: {load!r}')
            else:
                app.es_client_manager = EsClientManager.from_dict(
                    app, json.loads(data))
            return str(app.es_client_manager)

        elif 'save' in options:
            save = options.get('save')
            app.history.save_session(
                save, json.dumps(app.es_client_manager.to_dict()))
            return f'Session save as: {save!r}'

        elif 'remove' in options:
            remove = options.get('remove')
            if app.history.delete_session(remove):
                return f'Session removed: {remove!r}'
            else:
                raise PeekError(f'Session not found: {remove!r}')

        elif 'clear' in options:
            app.history.clear_sessions()
            return 'All sessions cleared'
        else:
            raise PeekError(f'Unknown options: {options}')
예제 #16
0
    def __call__(self, app, f=None, **options):
        directives = options.get('@')
        if not directives:
            return app.capture.status()

        # Only honor first directive
        directive = directives[0]
        if directive == 'start':
            return app.start_capture(f)

        elif directive == 'stop':
            return app.stop_capture()
        else:
            raise PeekError(f'Unknown capture directive: {directive}')
예제 #17
0
    def visit_bin_op_node(self, node: BinOpNode):
        left_operand = Ref()
        with self.consumer(lambda v: left_operand.set(v)):
            node.left_node.accept(self)

        right_operand = Ref()
        with self.consumer(lambda v: right_operand.set(v)):
            node.right_node.accept(self)

        op_func = self._bin_op_funcs.get(node.op_token.value, None)
        if op_func is None:
            raise PeekError(
                f'Unknown binary operator: {node.op_token.value!r}')
        self.consume(op_func(left_operand.get(), right_operand.get()))
예제 #18
0
    def visit_for_in_node(self, node: ForInNode):
        var_name = node.item.token.value
        items_ref = Ref()
        with self.consumer(lambda v: items_ref.set(v)):
            node.items.accept(self)
        items = items_ref.get()
        if not isinstance(items, list):
            raise PeekError(
                f'For in loop must operator over a list, got {items!r}')

        for i in items:
            self.context[var_name] = i
            for n in node.suite:
                n.accept(self)
예제 #19
0
 def set_current(self, x):
     if isinstance(x, str):
         name = x
         self._index_current = self._clients.index(self.get_client(name))
     elif isinstance(x, int):
         if x < 0 or x >= len(self._clients):
             raise PeekError(
                 f'Attempt to set ES client at invalid index {x!r}')
         self._index_current = x
     else:
         raise ValueError(
             f'Connection must be specified by either name or index, got {x!r}'
         )
     for listener in self.listeners:
         if listener.on_set(self) is False:
             break
예제 #20
0
    def __call__(self, app, **options):
        service = options.get('service', None)
        conn = options.get('conn', None)
        if service is None:
            if app.es_client_manager.current.hosts:
                host = urllib.parse.urlparse(app.es_client_manager.current.hosts.split(',')[0]).hostname
                service = f'HTTP@{host}'
            else:
                raise PeekError('Cannot infer service principal. Please specify explicitly')

        krb_es_client = krb_authenticate(
            app.es_client_manager.current if conn is None else app.es_client_manager.get_client(conn),
            service,
            options.get('username', None),
            options.get('name', None)
        )
        app.es_client_manager.add(krb_es_client)
        return app.es_client_manager.current.perform_request('GET', '/_security/_authenticate')
예제 #21
0
    def __call__(self, app, *args, **options):
        self.function_lookup = {v: k for k, v in app.vm.functions.items()}
        content = []
        for arg in args:
            content.append(
                json.dumps(arg,
                           cls=PeekEncoder,
                           app=app,
                           separators=(',', ':')))

        content = ' '.join(content)
        if 'file' in options:
            end = '\n'  # this does not make sense in interactive mode, so hardcode it for now
            fname = options.get('file')
            if not isinstance(fname, str):
                raise PeekError(f'file name must be string, got {fname!r}')
            with open(fname, 'a') as outs:
                outs.write(f'{content}{end}')
        else:
            return content
예제 #22
0
 def get_client(self, x=None):
     if x is None:
         return self.current
     elif isinstance(x, str):
         name = x
         if not name:
             raise ValueError('Name cannot be empty')
         for c in self._clients:
             if c.name == name:
                 return c
         else:
             raise ValueError(f'No client with name: {name!r}')
     elif isinstance(x, int):
         if x < 0 or x >= len(self._clients):
             raise PeekError(
                 f'Attempt to set ES client at invalid index [{x}]')
         return self._clients[x]
     else:
         raise ValueError(
             f'Connection must be specified by either name or index, got {x!r}'
         )
예제 #23
0
    def visit_func_call_node(self, node: FuncCallNode):
        if isinstance(node.name_node, NameNode):
            func = self.get_value(node.name_node.token.value)
        else:
            func_ref = Ref()
            with self.consumer(lambda v: func_ref.set(v)):
                node.name_node.accept(self)
            func = func_ref.get()
        if not callable(func):
            raise PeekError(
                f'{node.name_node!r} is not a callable, but {func!r}')

        func_symbols = Ref()
        with self.consumer(lambda v: func_symbols.set(v)):
            node.symbols_node.accept(self)

        func_args = Ref()
        with self.consumer(lambda v: func_args.set(v)):
            node.args_node.accept(self)

        for kv_node in node.kwargs_node.kv_nodes:
            assert isinstance(kv_node.key_node,
                              NameNode), f'{kv_node.key_node!r}'
        func_kwargs = Ref()
        with self.consumer(lambda v: func_kwargs.set(v)):
            self._do_visit_dict_node(node.kwargs_node, resolve_key_name=False)
        kwargs = func_kwargs.get()
        if func_symbols.get():
            kwargs['@'] = func_symbols.get()
        try:
            result = func(self.app, *func_args.get(), **kwargs)
            if node.is_stmt:
                self.app.display.info(result)
            else:
                self.consume(result)
        except Exception as e:
            _logger.exception(
                f'Error on invoking function: {node.name_node!r}')
            self.app.display.error(e)