def serveStaticResource(resource): """ Return a static image or resource """ # ban the robots that ignore robots.txt user_agent = request.headers.get('User-Agent') if user_agent: if user_agent.find('MJ12BOT') != -1: abort(403) if user_agent.find('ltx71') != -1: abort(403) if user_agent.find('Sogou') != -1: abort(403) # log certain kinds of files if resource.endswith('.cab'): # increment the firmware download counter fw = db.session.query(Firmware).\ filter(Firmware.filename == os.path.basename(resource)).\ options(joinedload('limits')).\ options(joinedload('vendor')).first() if not fw: abort(404) # check the user agent isn't in the blocklist for this firmware for md in fw.mds: req = db.session.query(Requirement).\ filter(Requirement.component_id == md.component_id).\ filter(Requirement.kind == 'id').\ filter(Requirement.value == 'org.freedesktop.fwupd').\ first() if req and user_agent and not _user_agent_safe_for_requirement( user_agent): return Response(response='detected fwupd version too old', status=412, mimetype="text/plain") # check the firmware vendor has no country block if fw.banned_country_codes: banned_country_codes = fw.banned_country_codes.split(',') geo = GeoIP.new(GeoIP.GEOIP_MEMORY_CACHE) country_code = geo.country_code_by_addr(_get_client_address()) if country_code and country_code in banned_country_codes: return Response( response='firmware not available from this IP range', status=451, mimetype="text/plain") # check any firmware download limits for fl in fw.limits: if not fl.user_agent_glob or fnmatch.fnmatch( user_agent, fl.user_agent_glob): datestr = _get_datestr_from_datetime(datetime.date.today() - datetime.timedelta(1)) cnt = _execute_count_star(db.session.query(Client).\ filter(Client.firmware_id == fw.firmware_id).\ filter(Client.datestr >= datestr)) if cnt >= fl.value: response = fl.response if not response: response = 'Too Many Requests' resp = Response(response=response, status=429, mimetype='text/plain') resp.headers['Retry-After'] = '86400' return resp # this is cached for easy access on the firmware details page if not fw.do_not_track: fw.download_cnt += 1 # log the client request if not fw.do_not_track: db.session.add( Client(addr=_addr_hash(_get_client_address()), firmware_id=fw.firmware_id, user_agent=user_agent)) db.session.commit() # firmware blobs if resource.startswith('downloads/'): return send_from_directory(app.config['DOWNLOAD_DIR'], os.path.basename(resource)) if resource.startswith('deleted/'): return send_from_directory(app.config['RESTORE_DIR'], os.path.basename(resource)) if resource.startswith('uploads/'): return send_from_directory(app.config['UPLOAD_DIR'], os.path.basename(resource)) # static files served locally return send_from_directory(os.path.join(app.root_path, 'static'), resource)
def _upload_firmware(): # verify the user can upload if not _user_can_upload(g.user): flash('User has not signed legal agreement', 'danger') return redirect(url_for('main.route_dashboard')) # used a custom vendor_id if 'vendor_id' in request.form: try: vendor_id = int(request.form['vendor_id']) except ValueError as e: flash('Failed to upload file: Specified vendor ID %s invalid' % request.form['vendor_id'], 'warning') return redirect(url_for('upload.route_firmware')) vendor = db.session.query(Vendor).filter(Vendor.vendor_id == vendor_id).first() if not vendor: flash('Failed to upload file: Specified vendor ID not found', 'warning') return redirect(url_for('upload.route_firmware')) else: vendor = g.user.vendor # security check if not vendor.check_acl('@upload'): flash('Permission denied: Failed to upload file for vendor: ' 'User with vendor %s cannot upload to vendor %s' % (g.user.vendor.group_id, vendor.group_id), 'warning') return redirect(url_for('upload.route_firmware')) # not correct parameters if not 'target' in request.form: return _error_internal('No target') if not 'file' in request.files: return _error_internal('No file') if request.form['target'] not in ['private', 'embargo', 'testing']: return _error_internal('Target not valid') # find remote, creating if required remote_name = request.form['target'] if remote_name == 'embargo': remote = vendor.remote else: remote = db.session.query(Remote).filter(Remote.name == remote_name).first() if not remote: return _error_internal('No remote for target %s' % remote_name) # if the vendor has uploaded a lot of firmware don't start changing the rules is_strict = len(vendor.fws) < 500 # load in the archive fileitem = request.files['file'] if not fileitem: return _error_internal('No file object') try: ufile = UploadedFile(is_strict=is_strict) for cat in db.session.query(Category): ufile.category_map[cat.value] = cat.category_id for pro in db.session.query(Protocol): ufile.protocol_map[pro.value] = pro.protocol_id for verfmt in db.session.query(Verfmt): ufile.version_formats[verfmt.value] = verfmt ufile.parse(os.path.basename(fileitem.filename), fileitem.read()) except (FileTooLarge, FileTooSmall, FileNotSupported, MetadataInvalid) as e: flash('Failed to upload file: ' + str(e), 'danger') return redirect(request.url) # check the file does not already exist fw = db.session.query(Firmware)\ .filter(or_(Firmware.checksum_upload_sha1 == ufile.fw.checksum_upload_sha1, Firmware.checksum_upload_sha256 == ufile.fw.checksum_upload_sha256)).first() if fw: if fw.check_acl('@view'): flash('Failed to upload file: A file with hash %s already exists' % fw.checksum_upload_sha1, 'warning') return redirect('/lvfs/firmware/%s' % fw.firmware_id) flash('Failed to upload file: Another user has already uploaded this firmware', 'warning') return redirect(url_for('upload.route_firmware')) # check the guid and version does not already exist fws = db.session.query(Firmware).all() fws_already_exist = [] for md in ufile.fw.mds: provides_value = md.guids[0].value fw = _filter_fw_by_id_guid_version(fws, md.appstream_id, provides_value, md.version) if fw: fws_already_exist.append(fw) # all the components existed, so build an error out of all the versions if len(fws_already_exist) == len(ufile.fw.mds): if g.user.check_acl('@robot') and 'auto-delete' in request.form: for fw in fws_already_exist: if fw.remote.is_public: flash('Firmware {} cannot be autodeleted as is in remote {}'.format( fw.firmware_id, fw.remote.name), 'danger') return redirect(url_for('upload.route_firmware')) if fw.user.user_id != g.user.user_id: flash('Firmware was not uploaded by this user', 'danger') return redirect(url_for('upload.route_firmware')) for fw in fws_already_exist: flash('Firmware %i was auto-deleted due to robot upload' % fw.firmware_id) _firmware_delete(fw) else: versions_for_display = [] for fw in fws_already_exist: for md in fw.mds: if not md.version_display in versions_for_display: versions_for_display.append(md.version_display) flash('Failed to upload file: A firmware file for this device with ' 'version %s already exists' % ','.join(versions_for_display), 'danger') return redirect('/lvfs/firmware/%s' % fw.firmware_id) # check if the file dropped a GUID previously supported for umd in ufile.fw.mds: new_guids = [guid.value for guid in umd.guids] for md in db.session.query(Component).\ filter(Component.appstream_id == umd.appstream_id): if md.fw.is_deleted: continue for old_guid in [guid.value for guid in md.guids]: if old_guid in new_guids: continue fw_str = str(md.fw.firmware_id) if g.user.check_acl('@qa') or g.user.check_acl('@robot'): flash('Firmware drops GUID {} previously supported ' 'in firmware {}'.format(old_guid, fw_str), 'warning') else: flash('Firmware would drop GUID {} previously supported ' 'in firmware {}'.format(old_guid, fw_str), 'danger') return redirect(request.url) # allow plugins to copy any extra files from the source archive for cffile in ufile.cabarchive_upload.values(): ploader.archive_copy(ufile.cabarchive_repacked, cffile) # allow plugins to add files ploader.archive_finalize(ufile.cabarchive_repacked, _get_plugin_metadata_for_uploaded_file(ufile)) # dump to a file download_dir = app.config['DOWNLOAD_DIR'] if not os.path.exists(download_dir): os.mkdir(download_dir) fn = os.path.join(download_dir, ufile.fw.filename) cab_data = ufile.cabarchive_repacked.save(compress=True) with open(fn, 'wb') as f: f.write(cab_data) # create parent firmware object settings = _get_settings() target = request.form['target'] fw = ufile.fw fw.vendor = vendor fw.user = g.user fw.addr = _get_client_address() fw.remote = remote fw.checksum_signed_sha1 = hashlib.sha1(cab_data).hexdigest() fw.checksum_signed_sha256 = hashlib.sha256(cab_data).hexdigest() fw.is_dirty = True fw.failure_minimum = settings['default_failure_minimum'] fw.failure_percentage = settings['default_failure_percentage'] # fix name for md in fw.mds: name_fixed = _fix_component_name(md.name, md.developer_name_display) if name_fixed != md.name: flash('Fixed component name from "%s" to "%s"' % (md.name, name_fixed), 'warning') md.name = name_fixed # verify each component has a version format for md in fw.mds: if not md.verfmt_with_fallback: flash('Component {} does not have required LVFS::VersionFormat'.\ format(md.appstream_id), 'warning') # add to database fw.events.append(FirmwareEvent(remote_id=remote.remote_id, user_id=g.user.user_id)) db.session.add(fw) db.session.commit() # ensure the test has been added for the firmware type ploader.ensure_test_for_fw(fw) # send out emails to anyone interested for u in fw.get_possible_users_to_email: if u == g.user: continue if u.get_action('notify-upload-vendor') and u.vendor == fw.vendor: send_email("[LVFS] Firmware has been uploaded", u.email_address, render_template('email-firmware-uploaded.txt', user=u, user_upload=g.user, fw=fw)) elif u.get_action('notify-upload-affiliate'): send_email("[LVFS] Firmware has been uploaded by affiliate", u.email_address, render_template('email-firmware-uploaded.txt', user=u, user_upload=g.user, fw=fw)) flash('Uploaded file %s to %s' % (ufile.fw.filename, target), 'info') # invalidate if target == 'embargo': remote.is_dirty = True g.user.vendor.remote.is_dirty = True db.session.commit() return redirect(url_for('firmware.route_show', firmware_id=fw.firmware_id))
def route_search(max_results=150): # no search results if 'value' not in request.args: return render_template('search.html', mds=None, search_size=-1, keywords_good=[], keywords_bad=[]) # components that match keywords = _split_search_string(request.args['value']) ids = db.session.query(Keyword.component_id).\ filter(Keyword.value.in_(keywords)).\ group_by(Keyword.component_id).\ having(func.count() == len(keywords)).\ subquery() mds = [] appstream_ids = [] vendors = [] for md in db.session.query(Component).join(ids).\ join(Firmware).join(Remote).filter(Remote.is_public).\ order_by(Component.version.desc()).\ limit(max_results*4): if md.appstream_id in appstream_ids: continue mds.append(md) appstream_ids.append(md.appstream_id) if md.fw.vendor not in vendors: vendors.append(md.fw.vendor) # get any vendor information as a fallback keywords_good = [] keywords_bad = [] if mds: keywords_good.extend(keywords) search_method = 'FW' else: search_method = 'AND' # always add vendor results for vendor in db.session.query(Vendor).\ filter(Vendor.visible_for_search): for kw in keywords: if vendor.keywords: if kw in vendor.keywords: if vendor not in vendors: vendors.append(vendor) if kw not in keywords_good: keywords_good.append(kw) break if vendor.display_name: if kw in _split_search_string(vendor.display_name): if vendor not in vendors: vendors.append(vendor) if kw not in keywords_good: keywords_good.append(kw) break for kw in keywords: if not kw in keywords_good: keywords_bad.append(kw) # this seems like we're over-logging but I'd like to see how people are # searching so we can tweak the algorithm used _add_search_event( SearchEvent(value=request.args['value'], addr=_addr_hash(_get_client_address()), count=len(mds) + len(vendors), method=search_method)) return render_template('search.html', mds=mds[:max_results], search_size=len(mds), vendors=vendors, keywords_good=keywords_good, keywords_bad=keywords_bad)