def run(self, argv): parser = OptionParser() parser.add_option("-f", "--file", dest="infile", action="store", type="string", default='', help="File to import.") parser.add_option("-s", "--source", dest="source", action="store", default=None, help="Source to use if not in file.") parser.add_option("-e", "--event", dest="event", action="store_true", default=False, help="Make event.") parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Print saved objects.") (opts, args) = parser.parse_args(argv) if not opts.infile: print "Need a file to parse." return f = open(opts.infile, 'r') data = f.read() f.close() ret = import_standards_doc(data, "Command Line", "Standards Import Script", make_event=opts.event, source=opts.source) if ret['success']: for k in ["events", "samples", "emails", "indicators"]: print "%s (%i)" % (k, len(ret[k])) if opts.verbose: for i in ret[k]: print "\t" + i else: print "Failure: %s" % ret['reason']
def run(self, argv): parser = OptionParser() parser.add_option("-f", "--file", dest="infile", action="store", type="string", default='', help="File to import.") parser.add_option("-s", "--source", dest="source", action="store", default=None, help="Source to use if not in file.") parser.add_option("-e", "--event", dest="event", action="store_true", default=False, help="Make event.") parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Print saved objects.") (opts, args) = parser.parse_args(argv) if not opts.infile: print "Need a file to parse." return f = open(opts.infile, 'r') data = f.read() f.close() ret = import_standards_doc(data, "Command Line", "Standards Import Script", hdr_events=opts.event, source=opts.source) if ret['success']: for k in ["events", "samples", "emails", "indicators"]: print "%s (%i)" % (k, len(ret[k])) if opts.verbose: for i in ret[k]: print "\t" + i else: print "Failure: %s" % ret['reason']
def upload_standards(request): """ Upload a standards document. :param request: Django request. :type request: :class:`django.http.HttpRequest` :returns: :class:`django.http.HttpResponse` """ std_form = UploadStandardsForm(request.user, request.POST, request.FILES) response = {'form': std_form.as_table(), 'success': False, 'message': ""} if request.method != "POST": response['message'] = "Must submit via POST." return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) if not std_form.is_valid(): response['message'] = "Form is invalid." return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) data = '' for chunk in request.FILES['filedata']: data += chunk make_event = std_form.cleaned_data['make_event'] source = std_form.cleaned_data['source'] reference = std_form.cleaned_data['reference'] # XXX: Add reference to form and handle here? status = import_standards_doc(data, request.user.username, "Upload", ref=reference, make_event=make_event, source=source) if not status['success']: response['message'] = status['reason'] return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) response['success'] = True response['message'] = render_to_string("import_results.html", { 'failed': status['failed'], 'imported': status['imported'] }) return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request))
def upload_standards(request): """ Upload a standards document. :param request: Django request. :type request: :class:`django.http.HttpRequest` :returns: :class:`django.http.HttpResponse` """ std_form = UploadStandardsForm(request.user, request.POST, request.FILES) response = { 'form': std_form.as_table(), 'success': False, 'message': "" } if request.method != "POST": response['message'] = "Must submit via POST." return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) if not std_form.is_valid(): response['message'] = "Form is invalid." return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) data = '' for chunk in request.FILES['filedata']: data += chunk make_event = std_form.cleaned_data['make_event'] source = std_form.cleaned_data['source'] reference = std_form.cleaned_data['reference'] # XXX: Add reference to form and handle here? status = import_standards_doc(data, request.user.username, "Upload", ref=reference, make_event=make_event, source=source) if not status['success']: response['message'] = status['reason'] return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) response['success'] = True response['message'] = render_to_string("import_results.html", {'failed' : status['failed'], 'imported' : status['imported']}) return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request))
def obj_create(self, bundle, **kwargs): """ Handles creating STIX documents through the API. :param bundle: Bundle to create the records associated with this STIX document. :type bundle: Tastypie Bundle object. :returns: Bundle object. :raises BadRequest: If a type_ is not provided or creation fails. """ analyst = bundle.request.user.username type_ = bundle.data.get('upload_type', None) if not type_: raise BadRequest('You must specify the upload type.') elif type_ not in ('file', 'xml'): raise BadRequest('Unknown or unsupported upload type. ' + type_) # Remove this so it doesn't get included with the fields upload del bundle.data['upload_type'] result = None # Extract common information source = bundle.data.get('source', None) method = bundle.data.get('method', None) reference = bundle.data.get('reference', None) me = bundle.data.get('make_event', False) # default to False for the event if not source: raise BadRequest('No Source was specified') if type_ == 'xml': filedata = bundle.data.get('xml', None) elif type_ == 'file': file_ = bundle.data.get('filedata', None) filedata = file_.read() if not filedata: raise BadRequest('No STIX content uploaded.') result = import_standards_doc(filedata, analyst, method, make_event=me, ref=reference, source=source) if not result: raise BadRequest('No upload type found.') if not result['success']: raise BadRequest(result['reason']) return bundle
def upload_standards(request): """ Upload a standards document. :param request: Django request. :type request: :class:`django.http.HttpRequest` :returns: :class:`django.http.HttpResponse` """ std_form = UploadStandardsForm(request.user, request.POST, request.FILES) response = { 'form': std_form.as_table(), 'success': False, 'message': "" } if request.method != "POST": response['message'] = "Must submit via POST." return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) if not std_form.is_valid(): response['message'] = "Form is invalid." return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) data = '' for chunk in request.FILES['filedata']: data += chunk make_event = std_form.cleaned_data['make_event'] source = std_form.cleaned_data['source'] # XXX: Add reference to form and handle here? status = import_standards_doc(data, request.user.username, "Upload", make_event=make_event, source=source) if not status['success']: response['message'] = status['reason'] return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) response['success'] = True msg = '<table class="vertical" width="353px">\n\t<thead></thead>\n\t<tbody>' msg += '<tr><td class="key">%s (%i)</td><td>' % ("Events", len(status['events'])) for id_ in status['events']: msg += "<a href=\"%s\">%s</a><br />" % (reverse('crits.events.views.view_event', args=[id_]), id_) msg += '</td></tr>' msg += '<tr><td class="key">%s (%i)</td><td>' % ("Samples", len(status['samples'])) for id_ in status['samples']: msg += "<a href=\"%s\">%s</a><br />" % (reverse('crits.samples.views.detail', args=[id_]), id_) msg += '</td></tr>' msg += '<tr><td class="key">%s (%i)</td><td>' % ("Emails", len(status['emails'])) for id_ in status['emails']: msg += "<a href=\"%s\">%s</a><br />" % (reverse('crits.emails.views.email_detail', args=[id_]), id_) msg += '</td></tr>' msg += '<tr><td class="key">%s (%i)</td><td>' % ("Indicators", len(status['indicators'])) for id_ in status['indicators']: msg += "<a href=\"%s\">%s</a><br />" % (reverse('crits.indicators.views.indicator', args=[id_]), id_) msg += '</td></tr>' response['message'] = msg return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request))
def execute_taxii_agent(hostname=None, https=None, feed=None, keyfile=None, certfile=None, start=None, end=None, analyst=None, method=None): ret = { 'Certificate': [], 'Domain': [], 'Email': [], 'Event': [], 'Indicator': [], 'IP': [], 'PCAP': [], 'RawData': [], 'Sample': [], 'successes': 0, 'failures': [], 'status': False, 'reason': '' } sc = manager.get_config('taxii_service') # XXX: Validate these! if not hostname: hostname = str(sc['hostname']) if not keyfile: keyfile = str(sc['keyfile']) if not certfile: certfile = str(sc['certfile']) if not feed: feed = str(sc['data_feed']) if https == None: https = sc['https'] create_events = sc['create_events'] # Last document's end time is our start time. if not start: last = taxii.Taxii.get_last() if last: start = pytz.utc.localize(last.end) # If start is a string, convert it to a datetime # YYYY-MM-DD HH:MM:SS if isinstance(start, str): start = pytz.utc.localize(parse(start, fuzzy=True)) # store the current time as the time of this request runtime = datetime.now(tzutc()) # End time is always now, unless specified. if not end: end = runtime # If end is a string, convert it to a datetime # YYYY-MM-DD HH:MM:SS if isinstance(end, str): end = pytz.utc.localize(parse(end, fuzzy=True)) # compare start and end to make sure: # 1) start time is before end time # 2) end time is not in the future if (start != None and start >= end) and end > runtime: ret['reason'] = "Bad timestamp(s)" return ret client = tc.HttpClient() if https: client.setUseHttps(True) client.setAuthType(tc.HttpClient.AUTH_CERT) client.setAuthCredentials({'key_file': keyfile, 'cert_file': certfile}) if settings.HTTP_PROXY: proxy = settings.HTTP_PROXY if not proxy.startswith('http://'): proxy = 'http://' + proxy client.setProxy(proxy, proxy_type=tc.HttpClient.PROXY_HTTPS) crits_taxii = taxii.Taxii() crits_taxii.runtime = runtime crits_taxii.end = end # Poll using 1.1 then 1.0 if that fails. poll_msg = tm11.PollRequest(message_id=tm11.generate_message_id(), collection_name=feed, poll_parameters=tm11.PollRequest.PollParameters(), exclusive_begin_timestamp_label=start, inclusive_end_timestamp_label=end) response = client.callTaxiiService2(hostname, '/poll/', t.VID_TAXII_XML_11, poll_msg.to_xml()) taxii_msg = t.get_message_from_http_response(response, poll_msg.message_id) if response.getcode() != 200 or taxii_msg.message_type == tm11.MSG_STATUS_MESSAGE: # Check if this is a TAXII 1.0 server and try again if response.info().getheader('X-TAXII-Content-Type') == t.VID_TAXII_XML_10: poll_msg = tm.PollRequest(message_id=tm.generate_message_id(), feed_name=feed, exclusive_begin_timestamp_label=start, inclusive_end_timestamp_label=end) response = client.callTaxiiService2(hostname, '/poll/', t.VID_TAXII_XML_10, poll_msg.to_xml()) taxii_msg = t.get_message_from_http_response(response, poll_msg.message_id) if response.getcode() != 200 or taxii_msg.message_type == tm.MSG_STATUS_MESSAGE: ret['reason'] = "%s: %s" % (taxii_msg.status_type, taxii_msg.message) return ret else: ret['reason'] = "%s: %s" % (taxii_msg.status_type, taxii_msg.message) return ret valid = tm.validate_xml(taxii_msg.to_xml()) if valid != True: ret['reason'] = "Invalid XML: %s" % valid return ret if taxii_msg.message_type != tm.MSG_POLL_RESPONSE: ret['reason'] = "No poll response. Unexpected message type: %s" % taxii_msg.message_type return ret ret['status'] = True if not taxii_msg.content_blocks: crits_taxii.save() return ret mid = taxii_msg.message_id for content_block in taxii_msg.content_blocks: data = parse_content_block(content_block, keyfile, certfile) if not data: ret['failures'].append(('No data found in content block', 'Data')) continue objs = import_standards_doc(data, analyst, method, ref=mid, make_event=create_events) for k in objs['imported']: ret['successes'] += 1 ret[k[0]].append(k[1]) for k in objs['failed']: ret['failures'].append(k) crits_taxii.save() return ret
def execute_taxii_agent(hostname=None, feed=None, keyfile=None, certfile=None, start=None, end=None, analyst=None, method=None): ret = { 'events': [], 'samples': [], 'emails': [], 'indicators': [], 'successes': 0, 'failures': 0, 'status': False, 'reason': '' } sc = manager.get_config('taxii_service') # XXX: Validate these! if not hostname: hostname = str(sc['hostname']) if not keyfile: keyfile = str(sc['keyfile']) if not certfile: certfile = str(sc['certfile']) if not feed: feed = str(sc['data_feed']) # Last document's end time is our start time. if not start: last = taxii.Taxii.get_last() if last: start = pytz.utc.localize(last.end) # If start is a string, convert it to a datetime # YYYY-MM-DD HH:MM:SS if isinstance(start, str): start = pytz.utc.localize(parse(start, fuzzy=True)) # store the current time as the time of this request runtime = datetime.now(tzutc()) # End time is always now, unless specified. if not end: end = runtime # If end is a string, convert it to a datetime # YYYY-MM-DD HH:MM:SS if isinstance(end, str): end = pytz.utc.localize(parse(end, fuzzy=True)) # compare start and end to make sure: # 1) start time is before end time # 2) end time is not in the future if (start != None and start >= end) and end > runtime: ret['reason'] = "Bad timestamp(s)" return ret client = tc.HttpClient() client.setUseHttps(True) client.setAuthType(tc.HttpClient.AUTH_CERT) client.setAuthCredentials({'key_file': keyfile, 'cert_file': certfile}) if settings.HTTP_PROXY: proxy = settings.HTTP_PROXY if not proxy.startswith('http://'): proxy = 'http://' + proxy client.setProxy(proxy, proxy_type=tc.HttpClient.PROXY_HTTPS) crits_taxii = taxii.Taxii() crits_taxii.runtime = runtime crits_taxii.end = end poll_msg = tm.PollRequest(message_id=tm.generate_message_id(), feed_name=feed, exclusive_begin_timestamp_label=start, inclusive_end_timestamp_label=end) response = client.callTaxiiService2(hostname, '/poll/', t.VID_TAXII_XML_10, poll_msg.to_xml()) if response.getcode() != 200: ret['reason'] = "Response is not 200 OK" return ret taxii_msg = t.get_message_from_http_response(response, poll_msg.message_id) valid = tm.validate_xml(taxii_msg.to_xml()) if valid != True: ret['reason'] = valid return ret if taxii_msg.message_type != tm.MSG_POLL_RESPONSE: ret['reason'] = "No poll response" return ret ret['status'] = True if not taxii_msg.content_blocks: crits_taxii.save() return ret mid = taxii_msg.message_id for content_block in taxii_msg.content_blocks: data = parse_content_block(content_block, keyfile, certfile) if not data: ret['failures'] += 1 continue objs = import_standards_doc(data, analyst, method, ref=mid, make_event=True) ret['successes'] += 1 for k in ["events", "samples", "emails", "indicators"]: for i in objs[k]: ret[k].append(i) crits_taxii.save() return ret
def obj_create(self, bundle, **kwargs): """ Handles creating STIX documents through the API. :param bundle: Bundle to create the records associated with this STIX document. :type bundle: Tastypie Bundle object. :returns: HttpResponse. """ analyst = bundle.request.user.username type_ = bundle.data.get('upload_type', None) content = {'return_code': 1, 'imported': [], 'failed': []} if not type_: content['message'] = 'You must specify the upload type.' self.crits_response(content) elif type_ not in ('file', 'xml'): content['message'] = 'Unknown or unsupported upload type. ' + type_ self.crits_response(content) # Remove this so it doesn't get included with the fields upload del bundle.data['upload_type'] # Extract common information source = bundle.data.get('source', None) method = bundle.data.get('method', None) reference = bundle.data.get('reference', None) me = bundle.data.get('make_event', False) # default to False for the event if not source: content['message'] = 'No Source was specified' self.crits_response(content) if type_ == 'xml': filedata = bundle.data.get('xml', None) elif type_ == 'file': file_ = bundle.data.get('filedata', None) filedata = file_.read() if not filedata: content['message'] = 'No STIX content uploaded.' self.crits_response(content) result = import_standards_doc(filedata, analyst, method, make_event=me, ref=reference, source=source) if len(result['imported']): for i in result['imported']: d = {} otype = i[0] obj = i[1] rname = self.resource_name_from_type(otype) url = reverse('api_dispatch_detail', kwargs={ 'resource_name': rname, 'api_name': 'v1', 'pk': str(obj.id) }) d['url'] = url d['type'] = otype d['id'] = str(obj.id) content['imported'].append(d) if len(result['failed']): for f in result['failed']: d = {'type': f[1], 'message': f[0]} content['failed'].append(d) if result['success']: content['return_code'] = 0 self.crits_response(content)
def execute_taxii_agent(hostname=None, https=None, feed=None, keyfile=None, certfile=None, start=None, end=None, analyst=None, method=None): ret = { 'Certificate': [], 'Domain': [], 'Email': [], 'Event': [], 'Indicator': [], 'IP': [], 'PCAP': [], 'RawData': [], 'Sample': [], 'successes': 0, 'failures': [], 'status': False, 'reason': '' } sc = get_config('taxii_service') # XXX: Validate these! if not hostname: hostname = str(sc['hostname']) if not keyfile: keyfile = str(sc['keyfile']) if not certfile: certfile = str(sc['certfile']) if not feed: feed = str(sc['data_feed']) if https == None: https = sc['https'] create_events = sc['create_events'] # Last document's end time is our start time. if not start: last = taxii.Taxii.get_last() if last: start = pytz.utc.localize(last.end) # If start is a string, convert it to a datetime # YYYY-MM-DD HH:MM:SS if isinstance(start, str): start = pytz.utc.localize(parse(start, fuzzy=True)) # store the current time as the time of this request runtime = datetime.now(tzutc()) # End time is always now, unless specified. if not end: end = runtime # If end is a string, convert it to a datetime # YYYY-MM-DD HH:MM:SS if isinstance(end, str): end = pytz.utc.localize(parse(end, fuzzy=True)) # compare start and end to make sure: # 1) start time is before end time # 2) end time is not in the future if (start != None and start >= end) and end > runtime: ret['reason'] = "Bad timestamp(s)" return ret client = tc.HttpClient() if https: client.setUseHttps(True) client.setAuthType(tc.HttpClient.AUTH_CERT) client.setAuthCredentials({'key_file': keyfile, 'cert_file': certfile}) if settings.HTTP_PROXY: proxy = settings.HTTP_PROXY if not proxy.startswith('http://'): proxy = 'http://' + proxy client.setProxy(proxy, proxy_type=tc.HttpClient.PROXY_HTTPS) crits_taxii = taxii.Taxii() crits_taxii.runtime = runtime crits_taxii.end = end # Poll using 1.1 then 1.0 if that fails. poll_msg = tm11.PollRequest(message_id=tm11.generate_message_id(), collection_name=feed, poll_parameters=tm11.PollRequest.PollParameters(), exclusive_begin_timestamp_label=start, inclusive_end_timestamp_label=end) response = client.callTaxiiService2(hostname, '/poll/', t.VID_TAXII_XML_11, poll_msg.to_xml()) taxii_msg = t.get_message_from_http_response(response, poll_msg.message_id) if response.getcode() != 200 or taxii_msg.message_type == tm11.MSG_STATUS_MESSAGE: # Check if this is a TAXII 1.0 server and try again if response.info().getheader('X-TAXII-Content-Type') == t.VID_TAXII_XML_10: poll_msg = tm.PollRequest(message_id=tm.generate_message_id(), feed_name=feed, exclusive_begin_timestamp_label=start, inclusive_end_timestamp_label=end) response = client.callTaxiiService2(hostname, '/poll/', t.VID_TAXII_XML_10, poll_msg.to_xml()) taxii_msg = t.get_message_from_http_response(response, poll_msg.message_id) if response.getcode() != 200 or taxii_msg.message_type == tm.MSG_STATUS_MESSAGE: ret['reason'] = "%s: %s" % (taxii_msg.status_type, taxii_msg.message) return ret else: ret['reason'] = "%s: %s" % (taxii_msg.status_type, taxii_msg.message) return ret valid = tm.validate_xml(taxii_msg.to_xml()) if valid != True: ret['reason'] = "Invalid XML: %s" % valid return ret if taxii_msg.message_type != tm.MSG_POLL_RESPONSE: ret['reason'] = "No poll response. Unexpected message type: %s" % taxii_msg.message_type return ret ret['status'] = True if not taxii_msg.content_blocks: crits_taxii.save() return ret mid = taxii_msg.message_id for content_block in taxii_msg.content_blocks: data = parse_content_block(content_block, keyfile, certfile) if not data: ret['failures'].append(('No data found in content block', 'Data')) continue objs = import_standards_doc(data, analyst, method, ref=mid, make_event=create_events) for k in objs['imported']: ret['successes'] += 1 ret[k[0]].append(k[1]) for k in objs['failed']: ret['failures'].append(k) crits_taxii.save() return ret
def upload_standards(request): """ Upload a standards document. :param request: Django request. :type request: :class:`django.http.HttpRequest` :returns: :class:`django.http.HttpResponse` """ std_form = UploadStandardsForm(request.user, request.POST, request.FILES) response = {'form': std_form.as_table(), 'success': False, 'message': ""} if request.method != "POST": response['message'] = "Must submit via POST." return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) if not std_form.is_valid(): response['message'] = "Form is invalid." return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) data = '' for chunk in request.FILES['filedata']: data += chunk make_event = std_form.cleaned_data['make_event'] source = std_form.cleaned_data['source'] # XXX: Add reference to form and handle here? status = import_standards_doc(data, request.user.username, "Upload", make_event=make_event, source=source) if not status['success']: response['message'] = status['reason'] return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request)) response['success'] = True msg = '<table class="vertical" width="353px">\n\t<thead></thead>\n\t<tbody>' msg += '<tr><td class="key">%s (%i)</td><td>' % ("Events", len(status['events'])) for id_ in status['events']: msg += "<a href=\"%s\">%s</a><br />" % (reverse( 'crits.events.views.view_event', args=[id_]), id_) msg += '</td></tr>' msg += '<tr><td class="key">%s (%i)</td><td>' % ("Samples", len(status['samples'])) for id_ in status['samples']: msg += "<a href=\"%s\">%s</a><br />" % (reverse( 'crits.samples.views.detail', args=[id_]), id_) msg += '</td></tr>' msg += '<tr><td class="key">%s (%i)</td><td>' % ("Emails", len(status['emails'])) for id_ in status['emails']: msg += "<a href=\"%s\">%s</a><br />" % (reverse( 'crits.emails.views.email_detail', args=[id_]), id_) msg += '</td></tr>' msg += '<tr><td class="key">%s (%i)</td><td>' % ("Indicators", len(status['indicators'])) for id_ in status['indicators']: msg += "<a href=\"%s\">%s</a><br />" % (reverse( 'crits.indicators.views.indicator', args=[id_]), id_) msg += '</td></tr>' response['message'] = msg return render_to_response('file_upload_response.html', {'response': json.dumps(response)}, RequestContext(request))
def obj_create(self, bundle, **kwargs): """ Handles creating STIX documents through the API. :param bundle: Bundle to create the records associated with this STIX document. :type bundle: Tastypie Bundle object. :returns: HttpResponse. """ analyst = bundle.request.user.username type_ = bundle.data.get('upload_type', None) content = {'return_code': 1, 'imported': [], 'failed': []} if not type_: content['message'] = 'You must specify the upload type.' self.crits_response(content) elif type_ not in ('file', 'xml'): content['message'] = 'Unknown or unsupported upload type. ' + type_ self.crits_response(content) # Remove this so it doesn't get included with the fields upload del bundle.data['upload_type'] # Extract common information source = bundle.data.get('source', None) method = bundle.data.get('method', None) reference = bundle.data.get('reference', None) me = bundle.data.get('make_event', False) # default to False for the event if not source: content['message'] = 'No Source was specified' self.crits_response(content) if type_ == 'xml': filedata = bundle.data.get('xml', None) elif type_ == 'file': file_ = bundle.data.get('filedata', None) filedata = file_.read() if not filedata: content['message'] = 'No STIX content uploaded.' self.crits_response(content) result = import_standards_doc(filedata, analyst, method, make_event = me, ref = reference, source = source) if len(result['imported']): for i in result['imported']: d = {} otype = i[0] obj = i[1] rname = self.resource_name_from_type(otype) url = reverse('api_dispatch_detail', kwargs={'resource_name': rname, 'api_name': 'v1', 'pk': str(obj.id)}) d['url'] = url d['type'] = otype d['id'] = str(obj.id) content['imported'].append(d) if len(result['failed']): for f in result['failed']: d = {'type': f[1], 'message': f[0]} content['failed'].append(d) if result['success']: content['return_code'] = 0 self.crits_response(content)