Example #1
0
def route_recover_with_secret(secret):

    # check we have the right token
    user = db.session.query(User).filter(User.password_recovery == secret).first()
    if not user:
        flash('No user with that recovery password', 'danger')
        return redirect(url_for('main.route_index'), 302)

    # user has since been disabled
    if user.auth_type == 'disabled':
        flash('User has been disabled since the recovery email was sent', 'danger')
        return redirect(url_for('main.route_index'), 302)

    # user waited too long
    if datetime.datetime.utcnow() > user.password_recovery_ts + datetime.timedelta(hours=24):
        flash('More than 24 hours elapsed since the recovery email was sent', 'warning')
        return redirect(url_for('main.route_index'), 302)

    # password is stored hashed
    password = _generate_password()
    user.password = password
    user.password_ts = None
    user.password_recovery = None
    user.password_recovery_ts = None
    user.mtime = datetime.datetime.utcnow()
    db.session.commit()

    # send email
    send_email("[LVFS] Your password has been reset",
               user.email_address,
               render_template('email-recover-password.txt',
                               user=user, password=password))
    flash('Your password has been reset and an email has been sent with the new details', 'info')
    return redirect(url_for('main.route_index'), 302)
Example #2
0
def route_recover():
    """
    Shows an account recovery panel for a user
    """
    if request.method != 'POST':
        return render_template('user-recover.html')
    if not 'username' in request.form:
        flash('Unable to recover user as no username', 'danger')
        return redirect(url_for('main.route_dashboard'))

    # check exists
    username = request.form['username']
    user = db.session.query(User).filter(User.username == username).first()
    if not user:
        flash('Unable to recover password as no username %s found' % username, 'warning')
        return redirect(url_for('main.route_index'), 302)

    # set the recovery password
    try:
        user.generate_password_recovery()
        db.session.commit()
    except RuntimeError as e:
        flash('Unable to recover password for %s: %s' % (username, str(e)), 'warning')
        return redirect(url_for('main.route_index'), 302)

    # send email
    send_email("[LVFS] Your login details",
               user.email_address,
               render_template('email-recover.txt', user=user))
    flash('An email has been sent with a recovery link', 'info')
    return redirect(url_for('main.route_index'), 302)
Example #3
0
def route_reset_by_admin(user_id):
    """ Reset the users password """

    # check exists
    user = db.session.query(User).filter(User.user_id == user_id).first()
    if not user:
        flash('No user matched!', 'danger')
        return redirect(url_for('main.route_dashboard'), 422)

    # security check
    if not user.vendor.check_acl('@manage-users'):
        flash('Permission denied: Unable to modify user as non-admin', 'danger')
        return redirect(url_for('main.route_dashboard'))

    # password is stored hashed
    password = _generate_password()
    user.password = password
    user.mtime = datetime.datetime.utcnow()
    user.password_ts = None
    db.session.commit()

    # send email
    send_email("[LVFS] Your password has been reset",
               user.email_address,
               render_template('email-modify-password.txt',
                               user=user, password=password))

    flash('Password has been reset and an email has been sent to the user', 'info')
    return redirect(url_for('users.route_admin', user_id=user_id))
Example #4
0
def _demote_back_to_testing(fw):

    # from the server admin
    user = db.session.query(User).filter(User.username == '*****@*****.**').first()
    if not user:
        return

    # send email to uploading user
    if fw.user.get_action('notify-demote-failures'):
        send_email("[LVFS] Firmware has been demoted",
                   fw.user.email_address,
                   render_template('email-firmware-demote.txt',
                                   user=fw.user, fw=fw))

    fw.mark_dirty()
    remote = db.session.query(Remote).filter(Remote.name == 'testing').first()
    remote.is_dirty = True

    # asynchronously sign straight away, even public remotes
    for r in set([remote, fw.remote]):
        r.is_dirty = True
        _async_regenerate_remote.apply_async(args=(r.remote_id,), queue='metadata', countdown=1)

    fw.remote_id = remote.remote_id
    fw.events.append(FirmwareEvent(remote_id=fw.remote_id, user_id=user.user_id))
    db.session.commit()
    _event_log('Demoted firmware {} as reported success {}%'.format(fw.firmware_id, fw.success))
def _user_email_report():

    # find all users
    for user in db.session.query(User)\
                          .filter(User.auth_type != 'disabled'):
        if not user.get_action('notify-non-public'):
            continue
        fws_embargo = []
        fws_testing = []
        for fw in user.fws:
            if fw.target_duration < datetime.timedelta(days=30):
                continue
            if fw.remote.name == 'testing':
                fws_testing.append(fw)
                continue
            if fw.remote.name.startswith('embargo'):
                fws_embargo.append(fw)
                continue
        if fws_embargo or fws_testing:
            send_email(
                "[LVFS] List of non-public firmware", user.email_address,
                render_template('email-non-public.txt',
                                user=user,
                                fws_embargo=fws_embargo,
                                fws_testing=fws_testing))
Example #6
0
def _delete_embargo_obsoleted_fw():

    # all embargoed firmware
    emails = defaultdict(list)
    for fw in db.session.query(Firmware)\
                        .join(Remote)\
                        .filter(Remote.name.startswith('embargo'))\
                        .order_by(Firmware.timestamp.asc()):

        # less than 6 months old
        if fw.target_duration < datetime.timedelta(days=30 * 6):
            continue

        # check that all the components are available with new versions
        all_newer = True
        print(fw.target_duration, fw.remote.name, fw.version_display)
        for md in fw.mds:
            md_newest = None
            for md_new in db.session.query(Component)\
                                    .join(Firmware)\
                                    .join(Remote)\
                                    .filter(Remote.is_public)\
                                    .filter(Component.appstream_id == md.appstream_id)\
                                    .order_by(Firmware.timestamp.asc()):
                if md_new > md or (md_newest and md_new > md_newest):
                    md_newest = md_new
                    break
            if not md_newest:
                all_newer = False
                print('no newer version of {} {}'.format(
                    md.appstream_id, md.version_display))
                break
            print('{} {} [{}] is newer than {} [{}]'.format(
                md.appstream_id, md_newest.version_display,
                md_newest.fw.remote.name, md.version_display,
                md.fw.remote.name))
        if not all_newer:
            continue

        # delete, but not purge for another 6 months...
        _firmware_delete(fw)

        # dedupe emails by user
        emails[fw.user].append(fw)

    # send email to the user that uploaded them, unconditionally
    for user in emails:
        send_email(
            "[LVFS] Firmware has been obsoleted", user.email_address,
            render_template('email-firmware-obsolete.txt',
                            user=user,
                            fws=emails[user]))

    # all done
    db.session.commit()
Example #7
0
def _user_disable_notify():

    # find all users that have not logged in for over one year, and have never
    # been warned
    now = datetime.datetime.utcnow()
    for user in db.session.query(User)\
                          .filter(User.auth_type != 'disabled')\
                          .filter(User.atime < now - datetime.timedelta(days=365))\
                          .filter(User.unused_notify_ts == None):
        # send email
        send_email("[LVFS] User account unused: ACTION REQUIRED",
                   user.email_address,
                   render_template('email-unused.txt', user=user))
        user.unused_notify_ts = now
        db.session.commit()
Example #8
0
def _demote_back_to_embargo(fw):

    # send email to uploading user
    if fw.user.notify_demote_failures:
        send_email("[LVFS] Firmware has been demoted",
                   fw.user.email_address,
                   render_template('email-firmware-demote.txt',
                                   user=fw.user, fw=fw))

    fw.mark_dirty()
    remote = fw.vendor.remote
    remote.is_dirty = True
    fw.remote_id = remote.remote_id
    fw.events.append(FirmwareEvent(fw.remote_id))
    db.session.commit()
    _event_log('Demoted firmware {} as reported success {}%%'.format(fw.firmware_id, fw.success))
Example #9
0
def _demote_back_to_testing(fw):

    # from the server admin
    user = db.session.query(User).filter(User.username == '*****@*****.**').first()
    if not user:
        return

    # send email to uploading user
    if fw.user.get_action('notify-demote-failures'):
        send_email("[LVFS] Firmware has been demoted",
                   fw.user.email_address,
                   render_template('email-firmware-demote.txt',
                                   user=fw.user, fw=fw))

    fw.mark_dirty()
    remote = db.session.query(Remote).filter(Remote.name == 'testing').first()
    remote.is_dirty = True
    fw.remote_id = remote.remote_id
    fw.events.append(FirmwareEvent(remote_id=fw.remote_id, user_id=user.user_id))
    db.session.commit()
    _event_log('Demoted firmware {} as reported success {}%'.format(fw.firmware_id, fw.success))
Example #10
0
def route_user_create(vendor_id):
    """ Add a user to the vendor """

    # check exists
    vendor = db.session.query(Vendor).filter(Vendor.vendor_id == vendor_id).first()
    if not vendor:
        flash('Failed to modify vendor: No a vendor with that group ID', 'warning')
        return redirect(url_for('vendors.route_list'), 302)

    # security check
    if not vendor.check_acl('@manage-users'):
        flash('Permission denied: Unable to modify vendor as non-admin', 'danger')
        return redirect(url_for('vendors.route_show', vendor_id=vendor_id))

    if not 'username' in request.form or not request.form['username']:
        flash('Unable to add user as no username', 'danger')
        return redirect(url_for('vendors.route_show', vendor_id=vendor_id))
    if not 'display_name' in request.form:
        flash('Unable to add user as no display_name', 'danger')
        return redirect(url_for('vendors.route_show', vendor_id=vendor_id))
    username = request.form['username'].lower()
    user = db.session.query(User).filter(User.username == username).first()
    if user:
        flash('Failed to add user: Username already exists', 'warning')
        return redirect(url_for('vendors.route_users', vendor_id=vendor_id), 302)

    # verify email
    if not _email_check(username):
        flash('Failed to add user: Invalid email address', 'warning')
        return redirect(url_for('users.route_list'), 302)

    # verify the username matches the allowed vendor glob
    if not g.user.check_acl('@admin'):
        if not vendor.username_glob:
            flash('Failed to add user: '******'Admin has not set the account policy for this vendor',
                  'warning')
            return redirect(url_for('vendors.route_users', vendor_id=vendor_id), 302)
        if not _verify_username_vendor_glob(username, vendor.username_glob):
            flash('Failed to add user: '******'Email address does not match account policy %s' % vendor.username_glob,
                  'warning')
            return redirect(url_for('vendors.route_users', vendor_id=vendor_id), 302)

    # add user
    if g.user.vendor.oauth_domain_glob:
        user = User(username=username,
                    display_name=request.form['display_name'],
                    auth_type='oauth',
                    vendor_id=vendor.vendor_id)
    else:
        user = User(username=username,
                    display_name=request.form['display_name'],
                    auth_type='local',
                    otp_secret=_otp_hash(),
                    vendor_id=vendor.vendor_id)
        # this is stored hashed
        password = _generate_password()
        user.password = password
    db.session.add(user)
    db.session.commit()

    # send email
    if user.auth_type == 'local':
        send_email("[LVFS] An account has been created",
                   user.email_address,
                   render_template('email-confirm.txt',
                                   user=user, password=password))

    # done!
    flash('Added user %i' % user.user_id, 'info')
    return redirect(url_for('vendors.route_users', vendor_id=vendor_id), 302)
Example #11
0
def route_modify_by_admin(user_id):
    """ Change details about the any user """

    # check exists
    user = db.session.query(User).filter(User.user_id == user_id).first()
    if not user:
        flash('No user matched!', 'danger')
        return redirect(url_for('main.route_dashboard'), 422)

    # security check
    if not user.vendor.check_acl('@manage-users'):
        flash('Permission denied: Unable to modify user as non-admin', 'danger')
        return redirect(url_for('main.route_dashboard'))
    if not g.user.check_acl('@admin') and 'vendor_id' in request.form:
        flash('Permission denied: Unable to modify group for user as non-admin', 'danger')
        return redirect(url_for('main.route_dashboard'))

    # user is being promoted, so check the manager already has this attribute
    if not user.check_acl('@vendor-manager') and 'vendor-manager' in request.form:
        if not g.user.check_acl('@add-action-vendor-manager'):
            flash('Permission denied: Unable to promote user to manager', 'danger')
            return redirect(url_for('main.route_dashboard'))
    if not user.check_acl('@researcher') and 'researcher' in request.form:
        if not g.user.check_acl('@add-action-researcher'):
            flash('Permission denied: Unable to promote user to researcher', 'danger')
            return redirect(url_for('main.route_dashboard'))
    if not user.check_acl('@analyst') and 'analyst' in request.form:
        if not g.user.check_acl('@add-action-analyst'):
            flash('Permission denied: Unable to promote user to analyst', 'danger')
            return redirect(url_for('main.route_dashboard'))
    if not user.check_acl('@qa') and 'qa' in request.form:
        if not g.user.check_acl('@add-action-qa'):
            flash('Permission denied: Unable to promote user to QA', 'danger')
            return redirect(url_for('main.route_dashboard'))
    if not user.check_acl('@approved-public') and 'approved-public' in request.form:
        if not g.user.check_acl('@add-action-approved-public'):
            flash('Permission denied: Unable to promote user to approved public', 'danger')
            return redirect(url_for('main.route_dashboard'))
    if not user.check_acl('@robot') and 'robot' in request.form:
        if not g.user.check_acl('@add-action-robot'):
            flash('Permission denied: Unable to mark user as robot', 'danger')
            return redirect(url_for('main.route_dashboard'))
    if not user.check_acl('@admin') and 'admin' in request.form:
        if not g.user.check_acl('@add-action-admin'):
            flash('Permission denied: Unable to mark user as admin', 'danger')
            return redirect(url_for('main.route_dashboard'))
    if not user.check_acl('@admin') and 'partner' in request.form:
        if not g.user.check_acl('@add-action-partner'):
            flash('Permission denied: Unable to mark user as partner', 'danger')
            return redirect(url_for('main.route_dashboard'))

    # set each optional thing in turn
    old_vendor = user.vendor
    for key in ['display_name', 'username', 'auth_type', 'vendor_id', 'auth_warning']:
        if key in request.form:
            value = request.form[key]
            if value == '':
                value = None
            setattr(user, key, value)

    # get the new human_user_id if specified
    if 'human_user' in request.form:
        username = request.form['human_user']
        if username:
            human_user = db.session.query(User).\
                                filter(User.username == username).first()
            if not human_user:
                flash('Failed to modify profile: Human user %s not found' % username, 'warning')
                return redirect(url_for('main.route_profile'), 302)
            user.human_user_id = human_user.user_id
        else:
            user.human_user_id = None

    # unchecked checkbuttons are not included in the form data
    for key in ['is_otp_enabled']:
        setattr(user, key, bool(key in request.form))
    for key in ['qa', 'analyst', 'vendor-manager', 'researcher',
                'approved-public', 'robot', 'admin', 'partner']:
        if key in request.form:
            if not user.get_action(key):
                user.actions.append(UserAction(value=key))
        else:
            action = user.get_action(key)
            if action:
                user.actions.remove(action)

    # password is optional, and hashed
    if 'password' in request.form and request.form['password']:
        user.password = request.form['password']

    # was disabled?
    if user.auth_type == 'disabled':
        if not user.dtime:
            user.dtime = datetime.datetime.utcnow()
    else:
        user.dtime = None

    user.mtime = datetime.datetime.utcnow()
    db.session.commit()

    # reparent any uploaded firmware
    is_dirty = False
    reparent = bool('reparent' in request.form)
    if old_vendor.vendor_id != user.vendor_id and reparent:
        for fw in db.session.query(Firmware).\
                    filter(Firmware.user_id == user.user_id):
            fw.vendor_id = user.vendor_id
            if fw.remote.name.startswith('embargo'):
                is_dirty = True
            fw.remote_id = user.vendor.remote.remote_id
        for ev in db.session.query(FirmwareEvent).\
                    filter(FirmwareEvent.user_id == user.user_id):
            ev.remote_id = user.vendor.remote.remote_id

    # fix event log
    if old_vendor.vendor_id != user.vendor_id:
        for ev in db.session.query(Event).\
                    filter(Event.user_id == user.user_id):
            ev.vendor_id = user.vendor_id

    # mark both remotes as dirty
    if is_dirty:
        user.vendor.remote.is_dirty = True
        old_vendor.remote.is_dirty = True
    db.session.commit()

    # send email
    if 'send_email' in request.form:
        if old_vendor.vendor_id != user.vendor_id:
            send_email("[LVFS] Your account has been moved",
                       user.email_address,
                       render_template('email-moved.txt',
                                       user=user,
                                       old_vendor=old_vendor,
                                       reparent=reparent))
        else:
            if user.auth_type == 'disabled':
                send_email("[LVFS] Your account has been disabled",
                           user.email_address,
                           render_template('email-disabled.txt', user=user))
            else:
                send_email("[LVFS] Your account has been updated",
                           user.email_address,
                           render_template('email-modify.txt', user=user))
        flash('Updated profile and sent a notification email to the user', 'info')
    else:
        flash('Updated profile', 'info')

    return redirect(url_for('users.route_admin', user_id=user_id))
Example #12
0
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))
Example #13
0
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018 Richard Hughes <*****@*****.**>
#
# SPDX-License-Identifier: GPL-2.0+
#
# pylint: disable=singleton-comparison,wrong-import-position

import os
import sys

# allows us to run this from the project root
sys.path.append(os.path.realpath('.'))

import lvfs as application

from lvfs.emails import send_email

# make compatible with Flask
app = application.app

if __name__ == '__main__':
    with app.test_request_context():
        send_email("[LVFS] Test email", '*****@*****.**', 'Still working')
Example #14
0
def route_promote(firmware_id, target):
    """
    Promote or demote a firmware file from one target to another,
    for example from testing to stable, or stable to testing.
     """

    # check valid
    if target not in ['stable', 'testing', 'private', 'embargo']:
        return _error_internal("Target %s invalid" % target)

    # check firmware exists in database
    fw = db.session.query(Firmware).filter(
        Firmware.firmware_id == firmware_id).first()
    if not fw:
        flash('No firmware {} exists'.format(firmware_id), 'danger')
        return redirect(url_for('firmware.route_firmware'))

    # security check
    if not fw.check_acl('@promote-' + target):
        flash('Permission denied: No QA access to {}'.format(firmware_id),
              'danger')
        return redirect(url_for('firmware.route_show',
                                firmware_id=firmware_id))

    # vendor has to fix the problems first
    if target in ['stable', 'testing'] and fw.problems:
        probs = []
        for problem in fw.problems:
            if problem.kind not in probs:
                probs.append(problem.kind)
        flash(
            'Firmware has problems that must be fixed first: %s' %
            ','.join(probs), 'warning')
        return redirect(
            url_for('firmware.route_problems', firmware_id=firmware_id))

    # set new remote
    if target == 'embargo':
        remote = fw.vendor.remote
    else:
        remote = db.session.query(Remote).filter(Remote.name == target).first()
    if not remote:
        return _error_internal('No remote for target %s' % target)

    # same as before
    if fw.remote.remote_id == remote.remote_id:
        flash('Cannot move firmware: Firmware already in that target', 'info')
        return redirect(
            url_for('firmware.route_target', firmware_id=firmware_id))

    # invalidate both the remote it "came from", the one it's "going to" and
    # also the remote of the vendor that uploaded it
    remote.is_dirty = True
    fw.remote.is_dirty = True
    fw.vendor_odm.remote.is_dirty = True

    # invalidate the firmware as we're waiting for the metadata generation
    fw.mark_dirty()

    # some tests only run when the firmware is in stable
    ploader.ensure_test_for_fw(fw)

    # also dirty any ODM remote if uploading on behalf of an OEM
    if target == 'embargo' and fw.vendor != fw.user.vendor:
        fw.user.vendor.remote.is_dirty = True

    # all okay
    fw.remote_id = remote.remote_id
    fw.events.append(
        FirmwareEvent(remote_id=fw.remote_id, user_id=g.user.user_id))
    db.session.commit()

    # send email
    for u in fw.get_possible_users_to_email:
        if u == g.user:
            continue
        if u.get_action('notify-promote'):
            send_email(
                "[LVFS] Firmware has been promoted", u.email_address,
                render_template('email-firmware-promoted.txt',
                                user=g.user,
                                fw=fw))

    flash('Moved firmware', 'info')

    return redirect(url_for('firmware.route_target', firmware_id=firmware_id))