def item_version_update(r, slug, version, counter, type): """ Update the given version - no counter change """ if type == "jetpack": version = get_object_with_related_or_404(JetVersion, jetpack__slug=slug, name=version, counter=counter) elif type == "capability": version = get_object_with_related_or_404(CapVersion, capability__slug=slug, name=version, counter=counter) # permission check if not version.author == r.user: return HttpResponseNotAllowed(HttpResponse("You're not the author of this version")) version.author = r.user version.name = r.POST.get("version_name", version.name) if type == "jetpack": version.manifest = r.POST.get("version_manifest", version.manifest) version.published = r.POST.get("version_published", version.published) version.content = r.POST.get("version_content", version.content) version.description = r.POST.get("version_description", version.description) version.status = r.POST.get("version_status", version.status) version.is_base = r.POST.get("version_is_base", version.is_base) version.save() return render_to_response('json/version_updated.json', {'version': version}, context_instance=RequestContext(r), mimetype='application/json')
def remove_attachment(request, revision_id): """ Remove attachment from PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ('[security] Attempt to remove attachment from revision ' '(%s) by non-owner (%s)' % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') uid = request.POST.get('uid', '').strip() attachment = get_object_with_related_or_404(Attachment, pk=uid, revisions=revision) if not attachment: log_msg = ('Attempt to remove a non existing attachment. attachment: ' '%s, revision: %s.' % (uid, revision_id)) log.warning(log_msg) return HttpResponseForbidden( 'There is no such attachment in %s' % escape( revision.package.full_name)) revision.attachment_remove(attachment) return render_json(request, "json/attachment_removed.json", {'revision': revision, 'attachment': attachment})
def remove_attachment(request, revision_id): """ Remove attachment from PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ('[security] Attempt to remove attachment from revision ' '(%s) by non-owner (%s)' % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') uid = request.POST.get('uid', '').strip() attachment = get_object_with_related_or_404(Attachment, pk=uid, revisions=revision) if not attachment: log_msg = ('Attempt to remove a non existing attachment. attachment: ' '%s, revision: %s.' % (uid, revision_id)) log.warning(log_msg) return HttpResponseForbidden('There is no such attachment in %s' % escape(revision.package.full_name)) revision.attachment_remove(attachment) return render_json(request, "json/attachment_removed.json", { 'revision': revision, 'attachment': attachment })
def _add_dependency(r, slug, type, depversion, version=None, counter=None): """ Add depversion to the item represented by slug """ if version: if type == 'jetpack': item_version = get_object_with_related_or_404(JetVersion, jetpack__slug=slug, name=version, counter=counter) item = item_version.jetpack elif type == 'capability': item_version = get_object_with_related_or_404(CapVersion, capability__slug=slug, name=version, counter=counter) item = item_version.capability else: Klass = Cap if type == 'jetpack' else Jet item = Klass.objects.get(slug=slug) item_version = item.base_version # protection (do not allow two versions of the same Cap) for c in item_version.capabilities.all(): if c.slug == depversion.slug: return HttpResponseNotAllowed(HttpResponse("")) item_version.capabilities.add(depversion) item_version.save() dependency_remove_url = reverse("jp_%s_remove_dependency" % type, args=[ item.slug, item_version.name, item_version.counter, depversion.slug, depversion.name, depversion.counter]) return (item_version, dependency_remove_url)
def get_package_revision(id_name, type_id, revision_number=None, version_name=None, latest=False): """ Return revision of the package """ if not (revision_number or version_name): # get default revision - one linked via Package:version package = get_object_with_related_or_404(Package, id_number=id_name, type=type_id) package_revision = package.latest if latest else package.version if not package_revision: log.critical("Package %s by %s has no latest or version " "revision" % (package, package.author)) raise Http404 elif revision_number: # get version given by revision number package_revision = get_object_with_related_or_404( PackageRevision, package__id_number=id_name, package__type=type_id, revision_number=revision_number ) elif version_name: # get version given by version name package_revision = get_object_with_related_or_404( PackageRevision, package__id_number=id_name, package__type=type_id, version_name=version_name ) # For unknown reason some revisions are not linked to any package if not package_revision.package: log.critical( "PackageRevision %d by %s is not related to any " "Package" % (package_revision.pk, package_revision.author) ) raise Http404 return package_revision
def remove_module(request, revision_id): """ Remove module from PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to remove a module from package (%s) " "by non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') filenames = request.POST.get('filename').split(',') revision.add_commit_message('module removed') try: removed_modules, removed_dirs = revision.modules_remove_by_path( filenames) except Module.DoesNotExist: log_msg = 'Attempt to delete a non existing module(s) %s from %s.' % ( str(filenames), revision_id) log.warning(log_msg) return HttpResponseForbidden('There is no such module in %s' % escape(revision.package.full_name)) return render_json( request, "json/module_removed.json", { 'revision': revision, 'removed_modules': simplejson.dumps(removed_modules), 'removed_dirs': simplejson.dumps(removed_dirs) })
def package_remove_attachment(r, id_number, type_id, revision_number): """ Remove attachment from PackageRevision """ revision = get_package_revision(id_number, type_id, revision_number) if r.user.pk != revision.author.pk: log_msg = ("[security] Attempt to remove attachment from package (%s) " "by non-owner (%s)" % (id_number, r.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') uid = r.POST.get('uid', '').strip() attachment = get_object_with_related_or_404(Attachment, pk=uid, revisions=revision) if not attachment: log_msg = ('Attempt to remove a non existing attachment. attachment: ' '%s, package: %s.' % (uid, id_number)) log.warning(log_msg) return HttpResponseForbidden( 'There is no such attachment in %s' % escape( revision.package.full_name)) revision.attachment_remove(attachment) return render_to_response("json/attachment_removed.json", {'revision': revision, 'attachment': attachment}, context_instance=RequestContext(r), mimetype='application/json')
def add_module(request, revision_id): """ Add new module to the PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to add a module to package (%s) by " "non-owner (%s)" % (id_number, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this %s' % escape(revision.package.get_type_name())) filename = request.POST.get('filename') mod = Module( filename=filename, author=request.user, code="""// %s.js - %s's module // author: %s""" % (filename, revision.package.full_name, request.user.get_profile())) try: mod.save() revision.module_add(mod) except FilenameExistException, err: mod.delete() return HttpResponseForbidden(escape(str(err)))
def _get_addon(user, revision_id): revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if ((not revision.package.active and user != revision.package.author) or revision.package.type != 'a'): # pretend add-on doesn't exist as it's a Library or is private raise Http404() return revision
def prepare_zip(request, revision_id): """ Prepare download zip This package is built asynchronously and we assume it works. It will be downloaded in %``get_zip`` """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if (not revision.package.active and request.user != revision.package.author): # pretend package doesn't exist as it's private raise Http404() hashtag = request.POST.get('hashtag') if not hashtag: return HttpResponseForbidden( 'Add-on Builder has been updated!' 'We have updated this part of the application. Please ' 'empty your cache and reload to get changes.') if not validator.is_valid('alphanum', hashtag): log.warning('[security] Wrong hashtag provided') return HttpResponseBadRequest("{'error': 'Wrong hashtag'}") log.info('[zip:%s] Addon added to queue' % hashtag) # caching tqueued = time.time() tkey = _get_zip_cache_key(request, hashtag) cache.set(tkey, tqueued, 120) # create zip file zip_source(pk=revision.pk, hashtag=hashtag, tqueued=tqueued) return HttpResponse('{"delayed": true}')
def add_module(request, revision_id): """ Add new module to the PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to add a module to package (%s) by " "non-owner (%s)" % (id_number, request.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this %s' % escape( revision.package.get_type_name())) filename = request.POST.get('filename') mod = Module( filename=filename, author=request.user, code="""// %s.js - %s's module // author: %s""" % (filename, revision.package.full_name, request.user.get_profile()) ) try: mod.save() revision.module_add(mod) except FilenameExistException, err: mod.delete() return HttpResponseForbidden(escape(str(err)))
def remove_module(request, revision_id): """ Remove module from PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to remove a module from package (%s) " "by non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') filenames = request.POST.get('filename').split(',') revision.add_commit_message('module removed') try: removed_modules, removed_dirs = revision.modules_remove_by_path( filenames) except Module.DoesNotExist: log_msg = 'Attempt to delete a non existing module(s) %s from %s.' % ( str(filenames), revision_id) log.warning(log_msg) return HttpResponseForbidden( 'There is no such module in %s' % escape( revision.package.full_name)) return render_json(request, "json/module_removed.json", {'revision': revision, 'removed_modules': simplejson.dumps(removed_modules), 'removed_dirs': simplejson.dumps(removed_dirs)})
def upload_attachment(request, revision_id): """ Upload new attachment to the PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) log.debug(revision) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to upload attachment to package (%s) " "by non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this %s' % escape( revision.package.get_type_name())) f = request.FILES.get('upload_attachment') filename = request.META.get('HTTP_X_FILE_NAME') if not f: log_msg = 'Path not found: %s, revision: %s.' % ( filename, revision_id) log.error(log_msg) return HttpResponseServerError('Path not found.') content = f.read() # try to force UTF-8 code, on error continue with original data try: content = unicode(content, 'utf-8') except: pass try: attachment = revision.attachment_create_by_filename( request.user, filename, content) except ValidationError, e: return HttpResponseForbidden( 'Validation errors.\n%s' % parse_validation_messages(e))
def upload_attachment(request, revision_id): """ Upload new attachment to the PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) log.debug(revision) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to upload attachment to package (%s) " "by non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this %s' % escape(revision.package.get_type_name())) f = request.FILES.get('upload_attachment') filename = request.META.get('HTTP_X_FILE_NAME') if not f: log_msg = 'Path not found: %s, revision: %s.' % (filename, revision_id) log.error(log_msg) return HttpResponseServerError('Path not found.') content = f.read() # try to force UTF-8 code, on error continue with original data try: content = unicode(content, 'utf-8') except: pass try: attachment = revision.attachment_create_by_filename( request.user, filename, content) except ValidationError, e: return HttpResponseForbidden('Validation errors.\n%s' % parse_validation_messages(e))
def _get_addon(user, revision_id): revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if ((not revision.package.active and user != revision.package.author) or revision.package.type != 'a'): # pretend add-on doesn't exist as it's a Library or is private raise Http404() return revision
def prepare_test(r, id_number, revision_number=None): """ Test XPI from data saved in the database """ revision = get_object_with_related_or_404( PackageRevision, package__id_number=id_number, package__type="a", revision_number=revision_number ) hashtag = r.POST.get("hashtag") if not hashtag: log.warning("[security] No hashtag provided") return HttpResponseForbidden('{"error": "No hashtag"}') if not validator.is_valid("alphanum", hashtag): log.warning("[security] Wrong hashtag provided") return HttpResponseForbidden("{'error': 'Wrong hashtag'}") if r.POST.get("live_data_testing", False): modules = [] for mod in revision.modules.all(): if r.POST.get(mod.filename, False): code = r.POST.get(mod.filename, "") if mod.code != code: mod.code = code modules.append(mod) attachments = [] for att in revision.attachments.all(): if r.POST.get(str(att.pk), False): code = r.POST.get(str(att.pk)) att.code = code attachments.append(att) response, rm_xpi_url = revision.build_xpi(modules, attachments, hashtag=hashtag) else: response, rm_xpi_url = revision.build_xpi(hashtag=hashtag) return HttpResponse('{"delayed": true, "rm_xpi_url": "%s"}' % rm_xpi_url)
def rename_attachment(request, revision_id): """ Rename an attachment in a PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to rename attachment in revision (%s) " "by non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') uid = request.POST.get('uid', '').strip() try: attachment = revision.attachments.get(pk=uid) except: log_msg = ('Attempt to rename a non existing attachment. attachment: ' '%s, revision: %s.' % (uid, revision)) log.warning(log_msg) return HttpResponseForbidden('There is no such attachment in %s' % escape(revision.package.full_name)) new_name = request.POST.get('new_filename') new_ext = request.POST.get('new_ext') or attachment.ext if not revision.validate_attachment_filename(new_name, new_ext): return HttpResponseForbidden( ('Sorry, there is already an attachment in your add-on ' 'with the name "%s.%s". Each attachment in your add-on ' 'needs to have a unique name.') % (new_name, attachment.ext)) attachment.filename = new_name attachment.ext = new_ext try: attachment = revision.update(attachment) except ValidationError, err: return HttpResponseForbidden(str(err))
def get_revisions_list_html(r, id_number): " returns revision list to be displayed in the modal window " package = get_object_with_related_or_404(Package, id_number=id_number) revisions = get_revisions_list(id_number) return render_to_response( "_package_revisions_list.html", {"package": package, "revisions": revisions}, context_instance=RequestContext(r) )
def prepare_test(r, id_number, revision_number=None): """ Test XPI from data saved in the database """ revision = get_object_with_related_or_404(PackageRevision, package__id_number=id_number, package__type='a', revision_number=revision_number) hashtag = r.POST.get('hashtag') if not hashtag: log.warning('[security] No hashtag provided') return HttpResponseForbidden('{"error": "No hashtag"}') if not validator.is_valid('alphanum', hashtag): log.warning('[security] Wrong hashtag provided') return HttpResponseForbidden("{'error': 'Wrong hashtag'}") # prepare codes to be sent to the task mod_codes = {} att_codes = {} if r.POST.get('live_data_testing', False): for mod in revision.modules.all(): if r.POST.get(mod.filename, False): code = r.POST.get(mod.filename, '') if mod.code != code: mod_codes[str(mod.pk)] = code for att in revision.attachments.all(): if r.POST.get(str(att.pk), False): code = r.POST.get(str(att.pk)) att_codes[str(att.pk)] = code tasks.xpi_build_from_model.delay(revision.pk, mod_codes=mod_codes, att_codes=att_codes, hashtag=hashtag) return HttpResponse('{"delayed": true}')
def prepare_zip(request, revision_id): """ Prepare download zip This package is built asynchronously and we assume it works. It will be downloaded in %``get_zip`` """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if not revision.package.active and request.user != revision.package.author: # pretend package doesn't exist as it's private raise Http404() hashtag = request.POST.get("hashtag") if not hashtag: return HttpResponseForbidden( "Add-on Builder has been updated!" "We have updated this part of the application. Please " "empty your cache and reload to get changes." ) if not validator.is_valid("alphanum", hashtag): log.warning("[security] Wrong hashtag provided") return HttpResponseBadRequest("{'error': 'Wrong hashtag'}") log.info("[zip:%s] Addon added to queue" % hashtag) # caching tqueued = time.time() tkey = _get_zip_cache_key(request, hashtag) cache.set(tkey, tqueued, 120) # create zip file zip_source(pk=revision.pk, hashtag=hashtag, tqueued=tqueued) return HttpResponse('{"delayed": true}')
def capability_version_edit(r, slug, version, counter): version = get_object_with_related_or_404(CapVersion, capability__slug=slug, name=version, counter=counter) item = version.capability other_versions = CapVersion.objects.filter_by_slug(slug=slug) type = "capability" page = "editor" return render_to_response('edit_item.html', locals(), context_instance=RequestContext(r))
def jetpack_version_edit(r, slug, version, counter): version = get_object_with_related_or_404(JetVersion, jetpack__slug=slug, name=version, counter=counter) item = version.jetpack type = "jetpack" page = "editor" other_versions = JetVersion.objects.filter_by_slug(slug=slug) return render_to_response('edit_item.html', locals(), context_instance=RequestContext(r))
def create_xpi_from_object(r, slug, version, counter): """ Get all data needed for the XPI creation from model call createXPI with the right data """ ver = get_object_with_related_or_404(JetVersion, jetpack__slug=slug, name=version, counter=counter) # prepare capabilities return createXPI(r, slug, ver.content, ver.description, ver.manifest, caps=ver.capabilities.all())
def remove_dependency(r, slug, version, counter, type, d_slug, d_version, d_counter): """ Remove dependency from item """ if type == 'jetpack': item_version = get_object_with_related_or_404(JetVersion, jetpack__slug=slug, name=version, counter=counter) elif type == 'capability': item_version = get_object_with_related_or_404(CapVersion, capability__slug=slug, name=version, counter=counter) dependency = get_object_with_related_or_404(CapVersion, capability__slug=d_slug, name=d_version, counter=d_counter) item_version.capabilities.remove(dependency) item_version.save() return render_to_response('json/dependency_removed.json', locals(), context_instance=RequestContext(r), mimetype='application/json')
def item_get_versions(r, slug, type): """ get all existing versions for the item """ Klass = Jet if type=="jetpack" else Cap item = get_object_with_related_or_404(Klass, slug=slug) return render_to_response('json/versions.json', { "versions": item.versions.all() }, context_instance=RequestContext(r), mimetype='application/json')
def download_module(request, pk): """ return a JSON with all module info """ module = get_object_with_related_or_404(Module, pk=pk) if not module.can_view(request.user): log_msg = "[security] Attempt to download private module (%s) by " "non-owner (%s)" % (pk, request.user) log.warning(log_msg) return HttpResponseForbidden("You are not the author of this module.") return HttpResponse(module.get_json())
def download_module(request, pk): """ return a JSON with all module info """ module = get_object_with_related_or_404(Module, pk=pk) if not module.can_view(request.user): log_msg = ("[security] Attempt to download private module (%s) by " "non-owner (%s)" % (pk, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this module.') return HttpResponse(module.get_json())
def get_package_revision(id, type, revision_number=None, version_name=None, latest=False): """ Return revision of the package """ if not (revision_number or version_name): # get default revision - one linked via Package:version package = get_object_with_related_or_404(Package, id_number=id, type=type) package_revision = package.latest if latest else package.version elif revision_number: # get version given by revision number package_revision = get_object_with_related_or_404(PackageRevision, package__id_number=id, package__type=type, revision_number=revision_number) elif version_name: # get version given by version name package_revision = get_object_with_related_or_404(PackageRevision, package__id_number=id, package__type=type, version_name=version_name) return package_revision
def get_revisions_list_html(request, revision_id): " returns revision list to be displayed in the modal window " current = get_object_with_related_or_404(PackageRevision, pk=revision_id) if not current.package.can_view(request.user): raise Http404 revisions = current.package.revisions.all() revision_number = int(current.revision_number) return render( request, "_package_revisions_list.html", {"package": current.package, "revisions": revisions, "revision_number": revision_number, "current": current}, )
def download_attachment(request, uid): """ Display attachment from PackageRevision """ attachment = get_object_with_related_or_404(Attachment, id=uid) if not attachment.can_view(request.user): log_msg = "[security] Attempt to download private attachment (%s) by " "non-owner (%s)" % (uid, request.user) log.warning(log_msg) return HttpResponseForbidden("You are not the author of this attachment.") response = serve(request, attachment.path, settings.UPLOAD_DIR, show_indexes=False) response["Content-Disposition"] = "filename=%s.%s" % (attachment.filename, attachment.ext) return response
def item_version_save_as_base(r, slug, version, counter, type): """ Update the given version - no counter change """ if type == "jetpack": version = get_object_with_related_or_404(JetVersion, jetpack__slug=slug, name=version, counter=counter) item = version.jetpack elif type == "capability": version = get_object_with_related_or_404(CapVersion, capability__slug=slug, name=version, counter=counter) item = version.capability # permission check if not item.can_be_updated_by(r.user): return HttpResponseNotAllowed(HttpResponse("")) version.is_base = True version.save() return render_to_response('json/version_saved_as_base.json', {'version': version}, context_instance=RequestContext(r), mimetype='application/json')
def get_revisions_list_html(r, id_number, revision_number=None): " returns revision list to be displayed in the modal window " package = get_object_with_related_or_404(Package, id_number=id_number) revisions = package.revisions.all() if revision_number: revision_number = int(revision_number) return render_to_response( '_package_revisions_list.html', { 'package': package, 'revisions': revisions, 'revision_number': revision_number }, context_instance=RequestContext(r))
def copy(request, revision_id): """ Copy package - create a duplicate of the Package, set user as author """ source = get_object_with_related_or_404(PackageRevision, pk=revision_id) log.debug("[copy: %s] Copying started from (%s)" % (revision_id, source)) # save package try: package = source.package.copy(request.user) except IntegrityError, err: log.critical(("[copy: %s] Package copy failed") % revision_id) return HttpResponseForbidden("You already have a %s with that name" % escape(source.package.get_type_name()))
def copy(request, revision_id): """ Copy package - create a duplicate of the Package, set user as author """ source = get_object_with_related_or_404(PackageRevision, pk=revision_id) log.debug('[copy: %s] Copying started from (%s)' % (revision_id, source)) # save package try: package = source.package.copy(request.user) except IntegrityError, err: log.critical(("[copy: %s] Package copy failed") % revision_id) return HttpResponseForbidden('You already have a %s with that name' % escape(source.package.get_type_name()))
def get_revisions_list_html(request, revision_id): " returns revision list to be displayed in the modal window " current = get_object_with_related_or_404(PackageRevision, pk=revision_id) if not current.package.can_view(request.user): raise Http404 revisions = current.package.revisions.all() revision_number = int(current.revision_number) return render( request, '_package_revisions_list.html', { 'package': current.package, 'revisions': revisions, 'revision_number': revision_number, 'current': current })
def get_package_revision(pk=None, id_name=None, type_id=None, revision_number=None, version_name=None, latest=False): """ Return revision of the package """ if not pk and not id_name: raise Http404 if not (revision_number or version_name): # get default revision - one linked via Package:version if pk: package = get_object_with_related_or_404(Package, pk=pk) else: package = get_object_with_related_or_404(Package, id_number=id_name, type=type_id) package_revision = package.latest if latest else package.version if not package_revision: log.critical("Package %s by %s has no latest or version " "revision" % (package, package.author)) raise Http404 elif revision_number: # get version given by revision number if pk: package_revision = get_object_with_related_or_404( PackageRevision, package__pk=pk, revision_number=revision_number) else: package_revision = get_object_with_related_or_404( PackageRevision, package__id_number=id_name, package__type=type_id, revision_number=revision_number) elif version_name: # get version given by version name if pk: package_revision = get_object_with_related_or_404( PackageRevision, package__pk=pk, version_name=version_name) else: package_revision = get_object_with_related_or_404( PackageRevision, package__id_number=id_name, package__type=type_id, version_name=version_name) # For unknown reason some revisions are not linked to any package if not package_revision.package: log.critical("PackageRevision %d by %s is not related to any " "Package" % (package_revision.pk, package_revision.author)) raise Http404 return package_revision
def remove_attachment(request, revision_id): """ Remove attachment from PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = "[security] Attempt to remove attachment from revision " "(%s) by non-owner (%s)" % ( revision_id, request.user, ) log.warning(log_msg) return HttpResponseForbidden("You are not the author of this Package") uid = request.POST.get("uid", "").strip() attachment = get_object_with_related_or_404(Attachment, pk=uid, revisions=revision) if not attachment: log_msg = "Attempt to remove a non existing attachment. attachment: " "%s, revision: %s." % (uid, revision_id) log.warning(log_msg) return HttpResponseForbidden("There is no such attachment in %s" % escape(revision.package.full_name)) revision.attachment_remove(attachment) return render_json(request, "json/attachment_removed.json", {"revision": revision, "attachment": attachment})
def package_download_xpi(r, id_number, revision_number=None): """ Edit package - only for the author """ revision = get_object_with_related_or_404( PackageRevision, package__id_number=id_number, package__type="a", revision_number=revision_number ) (stdout, stderr) = revision.build_xpi() if stderr and not settings.DEBUG: # XXX: this should also log the error in file xpi_remove(revision.get_sdk_dir()) return download_xpi(r, revision.get_sdk_name(), revision.package.get_unique_package_name(), revision.package.name)
def rename_module(request, revision_id): """ Rename a module in a PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to rename a module to package (%s) by " "non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') old_name = request.POST.get('old_filename') new_name = request.POST.get('new_filename') if old_name == 'main': return HttpResponseForbidden( 'Sorry, you cannot change the name of the main module.' ) if not revision.validate_module_filename(new_name): return HttpResponseForbidden( ('Sorry, there is already a module in your add-on ' 'with the name "%s". Each module in your add-on ' 'needs to have a unique name.') % new_name ) modules = revision.modules.all() module = None for mod in modules: if mod.filename == old_name: module = mod if not module: log_msg = 'Attempt to rename a non existing module %s from %s.' % ( old_name, revision_id) log.warning(log_msg) return HttpResponseForbidden( 'There is no such module in %s' % escape( revision.package.full_name)) module.filename = new_name revision.add_commit_message('module renamed') revision.update(module) return render_json(request, "json/module_renamed.json", {'revision': revision, 'module': module})
def get_revisions_list_html(request, id_number, revision_number=None): " returns revision list to be displayed in the modal window " package = get_object_with_related_or_404(Package, id_number=id_number) revisions = package.revisions.all() if revision_number: current = package.revisions.get(revision_number=revision_number) else: current = None if revision_number: revision_number = int(revision_number) return render(request, '_package_revisions_list.html', { 'package': package, 'revisions': revisions, 'revision_number': revision_number, 'current': current})
def rename_module(request, revision_id): """ Rename a module in a PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to rename a module to package (%s) by " "non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') old_name = request.POST.get('old_filename') new_name = request.POST.get('new_filename') if old_name == 'main': return HttpResponseForbidden( 'Sorry, you cannot change the name of the main module.') if not revision.validate_module_filename(new_name): return HttpResponseForbidden( ('Sorry, there is already a module in your add-on ' 'with the name "%s". Each module in your add-on ' 'needs to have a unique name.') % new_name) modules = revision.modules.all() module = None for mod in modules: if mod.filename == old_name: module = mod if not module: log_msg = 'Attempt to rename a non existing module %s from %s.' % ( old_name, revision_id) log.warning(log_msg) return HttpResponseForbidden('There is no such module in %s' % escape(revision.package.full_name)) module.filename = new_name revision.add_commit_message('module renamed') revision.update(module) return render_json(request, "json/module_renamed.json", { 'revision': revision, 'module': module })
def package_test_xpi(r, id_number, revision_number=None): """ Test XPI from data saved in the database """ revision = get_object_with_related_or_404( PackageRevision, package__id_number=id_number, package__type="a", revision_number=revision_number ) # support temporary data if r.POST.get("live_data_testing", False): modules = [] for mod in revision.modules.all(): if r.POST.get(mod.filename, False): code = r.POST.get(mod.filename, "") if mod.code != code: mod.code = code modules.append(mod) (stdout, stderr) = revision.build_xpi_test(modules) else: (stdout, stderr) = revision.build_xpi() if stderr and not settings.DEBUG: # XXX: this should also log the error in file xpi_remove(revision.get_sdk_dir()) # return XPI url and cfx command stdout and stderr return render_to_response( "json/test_xpi_created.json", { "stdout": stdout, "stderr": stderr, "test_xpi_url": reverse( "jp_test_xpi", args=[revision.get_sdk_name(), revision.package.get_unique_package_name(), revision.package.name], ), "download_xpi_url": reverse( "jp_download_xpi", args=[revision.get_sdk_name(), revision.package.get_unique_package_name(), revision.package.name], ), "rm_xpi_url": reverse("jp_rm_xpi", args=[revision.get_sdk_name()]), "addon_name": '"%s (%s)"' % (revision.package.full_name, revision.get_version_name()), }, context_instance=RequestContext(r), )
def download_attachment(request, uid): """ Display attachment from PackageRevision """ attachment = get_object_with_related_or_404(Attachment, id=uid) if not attachment.can_view(request.user): log_msg = ("[security] Attempt to download private attachment (%s) by " "non-owner (%s)" % (uid, request.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this attachment.') response = serve(request, attachment.path, settings.UPLOAD_DIR, show_indexes=False) response['Content-Disposition'] = 'filename=%s.%s' % (attachment.filename, attachment.ext) return response
def add_folder(request, revision_id): " adds an EmptyDir to a revision " revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to add a folder to revision (%s) by " "non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') foldername, root = (request.POST.get('name', ''), request.POST.get('root_dir')) dir = EmptyDir(name=foldername, author=request.user, root_dir=root) try: dir.save() revision.folder_add(dir) except FilenameExistException, err: dir.delete() return HttpResponseForbidden(escape(str(err)))
def remove_library(request, revision_id): " remove dependency from the library provided via POST " revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ( "[security] Attempt to remove library from revision (%s) by " "non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this %s' % escape(revision.package.get_type_name())) # TODO: make unlinking work with library_id instead of id number lib_id_number = request.POST.get('id_number') library = get_object_or_404(Package, id_number=lib_id_number) try: revision.dependency_remove_by_id_number(lib_id_number) except Exception, err: return HttpResponseForbidden(escape(err.__str__()))
def switch_sdk(request, revision_id): " switch SDK used to create XPI - sdk_id from POST " revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: return HttpResponseForbidden('You are not the author of this Add-on') sdk_id = request.POST.get('id', None) sdk = get_object_or_404(SDK, id=sdk_id) old_sdk = revision.sdk log.info('Addon %s (%s) switched from Add-on Kit version %s to %s' % (revision.package.full_name, revision.package.id_number, old_sdk.version, sdk.version)) revision.sdk = sdk revision.add_commit_message('Switched to Add-on Kit %s' % sdk.version) revision.save() return render_json(request, "json/sdk_switched.json", { 'revision': revision, 'sdk': sdk, 'sdk_lib': revision.get_sdk_revision() })
def assign_library(request, revision_id): " assign library to the package " revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to assign library to revision (%s) by " "non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') # TODO: make linking work with library_id instead of id number library = get_object_or_404(Package, type='l', id_number=request.POST['id_number']) if request.POST.get('use_latest_version', False): lib_revision = library.version else: lib_revision = library.latest try: revision.dependency_add(lib_revision) except Exception, err: return HttpResponseForbidden(str(err))
def update_library(request, revision_id): " update a dependency to a certain version " revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to update library in revision (%s) by " "non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this %s' % escape(revision.package.get_type_name())) # TODO: make updating work with library_id instead of id number lib_id_number = request.POST.get('id_number') lib_revision = request.POST.get('revision') library = get_object_or_404(PackageRevision, pk=lib_revision, package__id_number=lib_id_number) try: revision.dependency_update(library) except DependencyException, err: return HttpResponseForbidden(escape(err.__str__()))
def remove_folder(request, revision_id): " removes an EmptyDir from a revision " revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to remove a folder from revision (%s) " "by non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') foldername, root = (pathify(request.POST.get('name', '')), request.POST.get('root_dir')) try: folder = revision.folders.get(name=foldername, root_dir=root) except EmptyDir.DoesNotExist: response = None if root == 'data': response = revision.attachment_rmdir(foldername) if not response: log_msg = 'Attempt to delete a non existing folder %s from %s.' % ( foldername, revision_id) log.warning(log_msg) return HttpResponseForbidden('There is no such folder in %s' % escape(revision.package.full_name)) revision, removed_attachments, removed_emptydirs = response return render_json( request, 'json/%s_rmdir.json' % root, { 'revision': revision, 'path': foldername, 'removed_attachments': simplejson.dumps(removed_attachments), 'removed_dirs': simplejson.dumps(removed_emptydirs), 'foldername': foldername }) else: revision.folder_remove(folder) return render_json(request, "json/folder_removed.json", { 'revision': revision, 'folder': folder })
def latest_dependencies(request, revision_id): revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) out_of_date = revision.get_outdated_dependency_versions() return render_json(request, 'json/latest_dependencies.json', {'revisions': out_of_date})
def save(request, revision_id, type_id=None): """ Save package and modules @TODO: check how dynamic module loading affects save """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to save package (%s) by " "non-owner (%s)" % (revision.pk, request.user)) log.warning(log_msg) return HttpResponseForbidden('You are not the author of this Package') save_revision = False save_package = False start_version_name = revision.version_name start_revision_message = revision.message response_data = {} package_full_name = request.POST.get('full_name', False) jid = request.POST.get('jid', None) version_name = request.POST.get('version_name', False) if jid and not validator.is_valid('alphanum_plus', jid): return HttpResponseForbidden( escape(validator.get_validation_message('alphanum_plus'))) # validate package_full_name and version_name if version_name and not validator.is_valid('alphanum_plus', version_name): return HttpResponseForbidden( escape(validator.get_validation_message('alphanum_plus'))) # here we're checking if the *current* full_name is different than the # revision's full_name if package_full_name and package_full_name != revision.package.full_name: try: revision.set_full_name(package_full_name) except ValidationError: return HttpResponseForbidden( escape( validator.get_validation_message('alphanum_plus_space'))) except IntegrityError: return HttpResponseForbidden( 'You already have a %s with that name' % escape(revision.package.get_type_name())) else: save_package = True save_revision = True response_data['full_name'] = package_full_name package_description = request.POST.get('package_description', False) if package_description: save_package = True revision.package.description = package_description response_data['package_description'] = package_description extra_json = request.POST.get('package_extra_json') if extra_json is not None: # None means it wasn't submitted. We want to accept blank strings. save_revision = True try: revision.set_extra_json(extra_json, save=False) except JSONDecodeError: return HttpResponseBadRequest( 'Extra package properties were invalid JSON.') except IllegalFilenameException, e: return HttpResponseBadRequest(str(e)) except KeyNotAllowed, e: return HttpResponseForbidden(str(e))