Esempio n. 1
0
    def from_project(cls, ssh_key, project, owner):
        # calculate the hash of the ssh_key+project.key.id()
        import hashlib
        m = hashlib.md5()
        m.update(ssh_key)
        m.update(str(project.key.id()))
        ssh_key_hash = m.hexdigest()

        # do we have this wisp already?
        if not owner:
            entry = cls.query().filter(cls.ssh_key_hash == ssh_key_hash).get()
        else:
            entry = cls.query().filter(cls.ssh_key_hash == ssh_key_hash,
                                       cls.owner == owner.key).get()

        # create if we didn't find it
        if not entry:
            # generate new token and create new entry
            token = "%s" % generate_token(size=16, caselimit=True)
            entry = Wisp(name=project.name,
                         ssh_key=ssh_key,
                         ssh_key_hash=ssh_key_hash,
                         token=token,
                         project=project.key,
                         owner=owner.key)
            entry.put()

        return entry
Esempio n. 2
0
    def from_stock(cls, ssh_key, post_creation, dynamic_image_url,
                   image_disk_format, image_container_format, owner):
        # calculate the hash of the ssh_key+post_creation+dynamic_image_url
        import hashlib
        m = hashlib.md5()
        m.update(ssh_key)
        m.update(post_creation)
        m.update(dynamic_image_url)
        ssh_key_hash = m.hexdigest()

        # do we have this wisp already?
        if not owner:
            entry = cls.query().filter(cls.ssh_key_hash == ssh_key_hash).get()
        else:
            entry = cls.query().filter(cls.ssh_key_hash == ssh_key_hash,
                                       cls.owner == owner.key).get()

        # create if we didn't find it
        if not entry:
            # generate new token and create new entry
            token = "%s" % generate_token(size=16, caselimit=True)
            entry = Wisp(name='anonymous',
                         ssh_key=ssh_key,
                         ssh_key_hash=ssh_key_hash,
                         post_creation=post_creation,
                         dynamic_image_url=dynamic_image_url,
                         image_disk_format=image_disk_format,
                         image_container_format=image_container_format,
                         token=token,
                         owner=owner.key)
            entry.put()

        return entry
Esempio n. 3
0
    def get(self):
        # next url handling (in the event of veering off path to a page)
        url = self.request.get('next')

        if url:
            page = NextPages(url=url,
                             npid=utils.generate_token(size=12).lower())
            page.put()

        # card for slack
        if "slackbot" in self.request.headers.get('User-Agent').lower():
            return self.redirect(self.uri_for('slack-card'))

        # login with github only at this point
        try:
            scope = 'user:email'
            github_helper = github.GithubAuth(scope, npid=page.npid)

            # create a github login url and go
            login_url = github_helper.get_authorize_url()
            self.redirect(login_url)

        except Exception as ex:
            # add error notice for user TODO
            self.auth.unset_session()
            self.redirect('https://lucidworks.com/labs')
Esempio n. 4
0
	def get(self):
		# basics
		ip = self.request.remote_addr

		# setup channel to do page refresh
		channel_token = generate_token()
		refresh_channel = channel.create_channel(channel_token)

		# various pulldown initialization
		self.form.flavor.choices=[]
		self.form.wisp.choices=[]
		self.form.cloud.choices=[]

		# add list of user's flavors, if any
		flavors = Flavor.flavors_with_instances_on_sale()
		for flavor in flavors:
			self.form.flavor.choices.insert(0, (flavor.name, flavor.description))

		# used for determining element layout
		wisp = None
		cloud = None

		# if the user is logged in, we build out the list of their wisps
		if self.user_id:
			# lookup user's auth info and wisps
			user_info = User.get_by_id(long(self.user_id))
			wisps = Wisp.get_by_user(user_info.key)
			for wisp in wisps:
				self.form.wisp.choices.insert(0, (wisp.key.id(), wisp.name))
		
			# load clouds
			clouds = Cloud.get_by_user(user_info.key)

			# create default cloud if none
			if not clouds:
				cloud = Cloud.create_default(user_info.key)
				clouds.append(cloud)
				self.add_message("Default cloud created.", 'success')

			for cloud in clouds:
				self.form.cloud.choices.insert(0, (cloud.key.id(), cloud.name))

		# params build out (injects the last wisp, if there was one)
		params = {
			'remote_ip': ip,
			'wisp': wisp,
			'cloud': cloud,
			'refresh_channel': refresh_channel,
			'channel_token': channel_token 
		}

		return self.render_template('lab/launcher.html', **params)
Esempio n. 5
0
    def invite(cls, email, group, invitor):
        # do we have this combo already?
        entry = cls.query().filter(cls.email == email,
                                   cls.group == group).get()

        if not entry:
            # generate new token and create new entry
            token = "%s" % generate_token(size=16, caselimit=True)
            entry = GroupMembers(group=group,
                                 email=email,
                                 invitor=invitor,
                                 token=token,
                                 active=False)
            entry.put()

        return entry
Esempio n. 6
0
	def invite(cls, email, group, invitor):
		# do we have this combo already?
		entry = cls.query().filter(cls.email == email, cls.group == group).get()
		
		if not entry:
			# generate new token and create new entry 
			token = "%s" % generate_token(size=16, caselimit=True)
			entry = GroupMembers(
				group = group,
				email = email,
				invitor = invitor,
				token = token,
				active = False
			)
			entry.put()

		return entry
Esempio n. 7
0
	def from_stock(
		cls,
		ssh_key,
		post_creation,
		dynamic_image_url,
		image_disk_format,
		image_container_format,
		owner
	):
		# calculate the hash of the ssh_key+post_creation+dynamic_image_url
		import hashlib
		m = hashlib.md5()
		m.update(ssh_key)
		m.update(post_creation)
		m.update(dynamic_image_url)
		ssh_key_hash = m.hexdigest()

		# do we have this wisp already?
		if not owner:		
			entry = cls.query().filter(
				cls.ssh_key_hash == ssh_key_hash
			).get()
		else:
			entry = cls.query().filter(
				cls.ssh_key_hash == ssh_key_hash, 
				cls.owner == owner.key
			).get()
		
		# create if we didn't find it
		if not entry:
			# generate new token and create new entry 
			token = "%s" % generate_token(size=16, caselimit=True)
			entry = Wisp(
				name = 'anonymous',
				ssh_key = ssh_key,
				ssh_key_hash = ssh_key_hash,
				post_creation = post_creation,
				dynamic_image_url = dynamic_image_url,
				image_disk_format = image_disk_format,
				image_container_format = image_container_format,
				token = token,
				owner = owner.key
			)
			entry.put()

		return entry
Esempio n. 8
0
    def get(self):
        # load user information
        user_info = User.get_by_id(long(self.user_id))

        generate_api_token = self.request.get('generate_api_token')

        if generate_api_token == "1":
            user_info.api_token = utils.generate_token()
            user_info.put()
            return self.redirect_to('account-settings')

        # form fields
        self.form.username.data = user_info.username
        self.form.name.data = user_info.name
        self.form.email.data = user_info.email
        self.form.company.data = user_info.company
        self.form.country.data = user_info.country
        self.form.timezone.data = user_info.timezone
        self.form.ssh_key.data = user_info.ssh_key

        # extras
        params = {}
        params['tfenabled'] = user_info.tfenabled
        params['api_token'] = user_info.api_token

        # create holder token to setup 2FA - this will continue until user enables 2fa
        if user_info.tfenabled == False:
            secret = pyotp.random_base32()
            totp = pyotp.TOTP(secret)
            qrcode = totp.provisioning_uri("%s-%s" %
                                           (config.app_name, user_info.email))
            params['qrcode'] = qrcode
            params['secret'] = secret

            # update the user's key
            user_info.tfsecret = secret
            user_info.put()

        return self.render_template('user/settings.html', **params)
Esempio n. 9
0
	def from_project(
		cls,
		ssh_key,
		project,
		owner
	):
		# calculate the hash of the ssh_key+project.key.id()
		import hashlib
		m = hashlib.md5()
		m.update(ssh_key)
		m.update(str(project.key.id()))
		ssh_key_hash = m.hexdigest()

		# do we have this wisp already?
		if not owner:		
			entry = cls.query().filter(
				cls.ssh_key_hash == ssh_key_hash
			).get()
		else:
			entry = cls.query().filter(
				cls.ssh_key_hash == ssh_key_hash, 
				cls.owner == owner.key
			).get()
		
		# create if we didn't find it
		if not entry:
			# generate new token and create new entry 
			token = "%s" % generate_token(size=16, caselimit=True)
			entry = Wisp(
				name = project.name,
				ssh_key = ssh_key,
				ssh_key_hash = ssh_key_hash,
				token = token,
				project = project.key,
				owner = owner.key
			)
			entry.put()

		return entry
Esempio n. 10
0
	def post(self):
		# request basics
		ip = self.request.remote_addr

		# response, type, cross posting
		params = {}
		self.response.headers['Content-Type'] = "application/json"
		self.response.headers['Access-Control-Allow-Origin'] = '*'

		# check if this IP has any other bids open
		instancebid = InstanceBid.get_incomplete_by_ip(ip)


		# check we have an instancebid already
		if instancebid:
			# validate wisp
			if instancebid.wisp == None:
				instancebid.key.delete()
				return error_response(self, "Deleting bid because no wisp was associated.", 403, params)

			# load the payment address
			if instancebid.instance:
				instancebid.address = instancebid.instance.get().address
				instancebid.ask = instancebid.instance.get().ask
			else:
				# we should have an instance assosciated, so bail on this one
				instancebid.key.delete()
				return error_response(self, "Deleting bid because no instance was associated.", 403, params)

			params['response'] = "error"
			params['message'] = "The calling IP address already has an instance reservation in progress."
			params['instancebid'] = instancebid
			self.response.set_status(403)
			return self.render_template('api/bid.json', **params)	

		# load POSTed JSON
		try:
			request = json.loads(self.request.body)
		except Exception as ex:
			return error_response(self, "Failure in parsing request JSON.", 403, params)

		# load optional values or defaults
		# ipv4 (allow default)
		if 'requires_ipv4' in request:
			requires_ipv4 = request['requires_ipv4']
		else:
			requires_ipv4 = 0
		
		# ipv6 (allow default)
		if 'requires_ipv6' in request:
			requires_ipv6 = request['requires_ipv6']
		else:
			requires_ipv6 = 0

		# providers (allow default)
		if 'providers' in request:
			providers = request['providers']
		else:
			providers = [{u'id': 1, u'name': u'All Providers'}]		

		# flavors (required)
		if 'flavor' in request:
			flavor_name = request['flavor']
			flavor = Flavor.get_by_name(flavor_name)

			# check if flavor was found
			if not flavor:
				return error_response(self, "Flavor not found.", 403, params)

		else:
			return error_response(self, "Flavor name is required.", 403, params)

		# cloud (optional)
		if 'cloud_id' in request:
			cloud_id = request['cloud_id']
			cloud = Cloud.get_by_id(long(cloud_id))

			# check if cloud was found
			if not cloud:
				return error_response(self, "Cloud ID not found.", 403, params)
		else:
			cloud = None

		# disallow both a wisp and a callback_url
		if 'wisp_id' in request and 'callback_url' in request:
			return error_response(self, "A wisp and a callback URL may not be used together.", 403, params)

		# require either a wisp or a callback_url
		if 'wisp_id' not in request and 'callback_url' not in request:
			return error_response(self, "A valid wisp or a callback URL is required.", 403, params)

		# load the wisp, if there is one
		if 'wisp_id' in request:
			wisp_id = request['wisp_id']
			wisp = Wisp.get_by_id(long(wisp_id))
		else:
			wisp = None
		
		# load the callback URL, if there is one
		if 'callback_url' in request:
			callback_url = request['callback_url']
		elif wisp:
			callback_url = wisp.callback_url
		else:
			callback_url = ""

		# test we have a callback_url or a valid image in the wisp
		if callback_url > "":
			try:
				result = urlfetch.fetch(callback_url, deadline=5)
				if result.status_code > 399:
					return error_response(self, "The callback URL is unreachable.", 403, params)
				# test result's image URL
			except Exception as ex:
				return error_response(self, "The callback URL is unreachable.", 403, params)
		elif wisp:
			if wisp.image == None and wisp.dynamic_image_url == None and wisp.project == None:
				return error_response(self, "A valid wisp or a callback URL is required.", 403, params)

		# grab a new bid hash to use for the new bid
		token = generate_token(size=16)
		name = "smr-%s" % generate_token(size=8)

		# create a new bid
		instancebid = InstanceBid()
		instancebid.token = token
		instancebid.name = name
		instancebid.need_ipv4_address = bool(requires_ipv4)
		instancebid.need_ipv6_address = bool(requires_ipv6)
		instancebid.flavor = flavor.key
		instancebid.remote_ip = ip
		instancebid.appliances = providers # providers is already JSON
		instancebid.status = 0
		instancebid.callback_url = callback_url

		# expires in 5 minutes
		epoch_time = int(time.time())
		instancebid.expires = datetime.fromtimestamp(epoch_time+300)

		# add wisp, if present
		if wisp:
			instancebid.wisp = wisp.key
		
		# add cloud, if present
		if cloud:
			instancebid.cloud = cloud.key

		# update
		instancebid.put()

		# sleep for dev
		if config.debug:
			time.sleep(2)

		# reserve the instance
		InstanceBid.reserve_instance_by_token(instancebid.token)

		# get the address, if you got an instance
		if instancebid.instance:
			address = instancebid.instance.get().address
			ask = instancebid.instance.get().ask
		else:
			# no instance was reserved
			instancebid.key.delete()
			return error_response(self, "No valid instances were returned.", 403, params)
			
		# hack address and ask into instancebid object for template (not stored)
		instancebid.address = address
		instancebid.ask = ask

		# build out the response
		params['response'] = "success"
		params['message'] = "A new instance bid has been created."	
		params['instancebid'] = instancebid

		# return response and include cross site POST headers
		self.response.set_status(201)

		return self.render_template('api/bid.json', **params)