bool CCryptosaurEngine::ValidateAuthDescActual (CDatum dAuthDesc, const CString &sScope, CDatum dUserData)

//	ValidateAuthDescActual
//
//	Validates that dAuthDesc is valid authorization from the actual user.

	{
	CDatum dAuthToken = dAuthDesc.GetElement(FIELD_AUTH_TOKEN);
	CDatum dCredentials = dAuthDesc.GetElement(FIELD_CREDENTIALS);

	//	Do we have an authToken?

	if (!dAuthToken.IsNil())
		{
		//	Get the key to sign with (the key is guaranteed to exist because we
		//	checked at boot time).

		CIPInteger *pAuthTokenKey = m_Keys.GetAt(KEY_CRYPTOSAUR_AUTH_TOKEN);

		//	Validate

		CDatum dData;
		if (!CCryptosaurInterface::ValidateAuthToken(dAuthToken, *pAuthTokenKey, &dData))
			return false;

		//	The proper user?

		if (!strEquals(strToLower(dData.GetElement(FIELD_USERNAME)), strToLower(dUserData.GetElement(FIELD_USERNAME))))
			return false;
		
		//	AuthToken for actual?

		if (!dData.GetElement(FIELD_SCOPE).IsNil())
			return false;

		//	OK

		return true;
		}

	//	Otherwise, we better have credentials

	else if (!dCredentials.IsNil())
		{
		//	Compare credentials against user record

		CDatum dTrueAuthDesc = dUserData.GetElement(FIELD_AUTH_DESC);
		if (!((const CIPInteger &)dCredentials == (const CIPInteger &)dTrueAuthDesc.GetElement(FIELD_CREDENTIALS)))
			return false;

		//	OK

		return true;
		}

	//	Otherwise we fail.

	else
		return false;
	}
Beispiel #2
0
void CAeonView::CreateSecondaryData (const CTableDimensions &PrimaryDims, const CRowKey &PrimaryKey, CDatum dFullData, SEQUENCENUMBER RowID, CDatum *retdData)

//	CreateSecondaryData
//
//	Creates the data for a secondary view row.

	{
	int i, j;
	CComplexStruct *pData = new CComplexStruct;

	//	If the list of columns is empty then we just add the primary key

	if (m_Columns.GetCount() == 0)
		pData->SetElement(FIELD_PRIMARY_KEY, PrimaryKey.AsDatum(PrimaryDims));

	//	Otherwise we add all the fields listed in the columns array

	else
		{
		for (i = 0; i < m_Columns.GetCount(); i++)
			{
			//	The special string "primaryKey" means that we insert the 
			//	primary key as a special field.

			if (strEquals(m_Columns[i], FIELD_PRIMARY_KEY))
				pData->SetElement(FIELD_PRIMARY_KEY, PrimaryKey.AsDatum(PrimaryDims));

			//	The special string "*" means that we insert all existing
			//	fields.

			else if (strEquals(m_Columns[i], STR_ALL_COLUMNS))
				{
				for (j = 0; j < dFullData.GetCount(); j++)
					{
					CDatum dKey = dFullData.GetKey(j);
					CDatum dValue = dFullData.GetElement(j);

					if (!dValue.IsNil())
						pData->SetElement(dKey, dValue);
					}
				}

			//	Add the field by name.

			else
				{
				CDatum dColData = dFullData.GetElement(m_Columns[i]);
				if (!dColData.IsNil())
					pData->SetElement(m_Columns[i], dColData);
				}
			}
		}

	//	Done

	*retdData = CDatum(pData);
	}
Beispiel #3
0
bool CDatum::IsEqual (CDatum dValue) const

//	IsEqual
//
//	Returns TRUE if the values are equal

	{
	switch (GetBasicType())
		{
		case typeNil:
			return dValue.IsNil();

		case typeTrue:
			return !dValue.IsNil();

		case typeInteger32:
		case typeInteger64:
		case typeIntegerIP:
		case typeDouble:
			return (dValue.IsNumber() && CNumberValue(*this).Compare(dValue) == 0);

		case typeString:
			return (dValue.GetBasicType() == typeString && strEquals(*this, dValue));

		case typeDateTime:
			return (dValue.GetBasicType() == typeDateTime && ((const CDateTime &)*this == (const CDateTime &)dValue));

		//	LATER
		case typeArray:
		case typeBinary:
		case typeStruct:
		case typeSymbol:
			return false;

		default:
			ASSERT(false);
			return false;
		}
	}
Beispiel #4
0
void CMnemosynthDb::IncorporateDelta (CDatum dPayload)

//	IncorporateDelta
//
//	Incorporates the delta data

	{
	CSmartLock Lock(m_cs);

	int i;

	//	Get various elements

	CDatum dCollections = dPayload.GetElement(STR_COLLECTIONS);
	CDatum dEndpoint = dPayload.GetElement(STR_ENDPOINT);
	CDatum dEntries = dPayload.GetElement(STR_ENTRIES);
	DWORD dwProcessID = dPayload.GetElement(FIELD_PROCESS_ID);

	//	Make sure the endpoint exists

	SEndpoint *pEndpoint = GetOrAddEndpoint(dEndpoint, dwProcessID);

	DWORD dwOriginalSeq = pEndpoint->dwSeqRecv;
	DWORD dwMaxSeq = dwOriginalSeq;

	//	Loop over all entries

	for (i = 0; i < dEntries.GetCount(); i++)
		{
		CDatum dEntry = dEntries.GetElement(i);
		DWORD dwSeq = (DWORD)(int)dEntry.GetElement(3);
		if (dwSeq > dwOriginalSeq)
			{
			//	LATER: Detect and resolve conflicts

			if (dwSeq > dwMaxSeq)
				dwMaxSeq = dwSeq;

			const CString &sCollection = dCollections.GetElement((int)dEntry.GetElement(0));
			const CString &sKey = dEntry.GetElement(1);
			CDatum dValue = dEntry.GetElement(2);

			//	If we're not CentralModule and we get a deletion, then delete
			//	right away. If we're CentralModule then we incorporate because
			//	we will send it out on the next update.

			if (dValue.IsNil() && !m_pProcess->IsCentralModule())
				{
				DeleteEntry(sCollection, sKey);
#ifdef DEBUG_MNEMOSYNTH
				printf("Delete entry: %s/%s\n", (LPSTR)sCollection, (LPSTR)sKey);
#endif
				}

			//	Incorporate

			else
				{
				SEntry *pEntry = GetWriteEntry(sCollection, sKey);
				pEntry->dValue = dValue;
				pEntry->dwOwnerID = pEndpoint->dwID;
				pEntry->dwSequence = dwSeq;

#ifdef DEBUG_MNEMOSYNTH
				printf("Modify entry: %s/%s [owner = %s seq = %d]\n", (LPSTR)sCollection, (LPSTR)sKey, (LPSTR)pEndpoint->sName, dwSeq);
#endif
				}
			}
#ifdef DEBUG_MNEMOSYNTH
		else
			{
			printf("%s: Skipping %s because %d <= %d\n", (LPSTR)m_pProcess->GetModuleName(), (LPSTR)dCollections.GetElement((int)dEntry.GetElement(0)).AsString(), dwSeq, dwOriginalSeq);
			}
#endif
		}

	//	Done

	pEndpoint->dwSeqRecv = dwMaxSeq;
	}
Beispiel #5
0
bool CUserInfoSession::OnProcessMessage (const SArchonMessage &Msg)

//	OnProcessMessage
//
//	We received a reply from Aeon

	{
	int i;

	//	If this is an error, then we return the error back to the client

	if (IsError(Msg))
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, Msg.dPayload);
		return false;
		}

	//	If we're waiting for the user record, then see if we can process it now.

	if (m_iState == stateWaitingForUserRecord)
		{
		//	Cryptosaur.getUser

		if (strEquals(GetOriginalMsg().sMsg, MSG_CRYPTOSAUR_GET_USER))
			{
			CDatum dUserData = Msg.dPayload;

			//	If the user does not exist, then we return Nil

			if (dUserData.IsNil())
				{
				SendMessageReply(MSG_REPLY_DATA, CDatum());
				return false;
				}

			//	Generate a sanitized user record

			CComplexStruct *pReply = new CComplexStruct;
			pReply->SetElement(FIELD_USERNAME, dUserData.GetElement(FIELD_USERNAME));

			//	Sanitize rights

			CDatum dRights = dUserData.GetElement(FIELD_RIGHTS);
			if (!m_sScope.IsEmpty())
				{
				CComplexArray *pRights = new CComplexArray;

				for (i = 0; i < dRights.GetCount(); i++)
					if (strStartsWith(dRights.GetElement(i), m_sScope))
						pRights->Insert(dRights.GetElement(i));

				pReply->SetElement(FIELD_RIGHTS, CDatum(pRights));
				}
			else
				pReply->SetElement(FIELD_RIGHTS, dRights);

			//	Done

			SendMessageReply(MSG_REPLY_DATA, CDatum(pReply));
			return false;
			}

		//	If we get back nil then the user does not exist.

		else if (Msg.dPayload.IsNil())
			{
			SendMessageReplyError(MSG_ERROR_DOES_NOT_EXIST, strPattern(ERR_UNKNOWN_USERNAME, m_sUsername));
			return false;
			}

		//	Otherwise, we handle the result based on the original message

		else if (strEquals(GetOriginalMsg().sMsg, MSG_CRYPTOSAUR_CHECK_PASSWORD_SHA1))
			{
			//	Get the parameters from the original message

			CDatum dChallenge = GetOriginalMsg().dPayload.GetElement(1);
			CDatum dResponse = GetOriginalMsg().dPayload.GetElement(2);

			//	Get the password has from the response

			CDatum dAuthDesc = Msg.dPayload.GetElement(FIELD_AUTH_DESC);
			CDatum dPasswordHash = dAuthDesc.GetElement(FIELD_CREDENTIALS);

			//	Create a response to the challenge based on the password hash that
			//	we have stored.

			CDatum dCorrect = CAI1Protocol::CreateSHAPasswordChallengeResponse(dPasswordHash, dChallenge);

			//	Compare the correct response to the actual

			if ((const CIPInteger &)dResponse == (const CIPInteger &)dCorrect)
				return UpdateLoginSuccess(stateWaitingForSuccessUpdate);
			else
				return UpdateLoginFailure();
			}

		//	Cryptosaur.hasRights

		else if (strEquals(GetOriginalMsg().sMsg, MSG_CRYPTOSAUR_HAS_RIGHTS))
			{
			CDatum dRights = Msg.dPayload.GetElement(FIELD_RIGHTS);
			CDatum dRightsRequired = m_dPayload.GetElement(1);

			//	Get the rights from the user

			CAttributeList Rights;
			dRights.AsAttributeList(&Rights);

			//	Check

			for (i = 0; i < dRightsRequired.GetCount(); i++)
				{
				if (!Rights.HasAttribute(dRightsRequired.GetElement(i)))
					{
					SendMessageReply(MSG_REPLY_DATA, CDatum());
					return false;
					}
				}

			//	We have all rights

			SendMessageReply(MSG_REPLY_DATA, CDatum(CDatum::constTrue));
			return false;
			}

		//	Cryptosaur.loginUser

		else if (strEquals(GetOriginalMsg().sMsg, MSG_CRYPTOSAUR_LOGIN_USER))
			{
			//	Get the parameters from the original message

			CDatum dRequestAuthDesc = GetOriginalMsg().dPayload.GetElement(1);
			CDatum dCredentials = dRequestAuthDesc.GetElement(FIELD_CREDENTIALS);
			CDatum dChallengeCredentials = dRequestAuthDesc.GetElement(FIELD_CHALLENGE_CREDENTIALS);
			CDatum dPassword = dRequestAuthDesc.GetElement(FIELD_PASSWORD);
			m_bActual = !dRequestAuthDesc.GetElement(FIELD_ACTUAL).IsNil();

			if (!dRequestAuthDesc.GetElement(FIELD_AUTH_TOKEN_INFINITE).IsNil())
				m_dwAuthTokenLifetime = 0;
			else
				{
				m_dwAuthTokenLifetime = (DWORD)(int)dRequestAuthDesc.GetElement(FIELD_AUTH_TOKEN_LIFETIME);
				if (m_dwAuthTokenLifetime == 0)
					m_dwAuthTokenLifetime = DEFAULT_AUTH_TOKEN_TIMEOUT;
				}

			//	If we're not actual and have no scope, then we can't continue

			if (!m_bActual && m_sScope.IsEmpty())
				{
				SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, ERR_SCOPE_REQUIRED);
				return false;
				}

			//	User data

			CDatum dUserData = Msg.dPayload;
			CDatum dAuthDesc;
			if (m_bActual)
				dAuthDesc = dUserData.GetElement(FIELD_AUTH_DESC);
			else
				dAuthDesc = dUserData.GetElement(strPattern("%s%s", m_sScope, FIELD_AUTH_DESC));

			//	If we have no authdesc, then we can't continue. This is likely 
			//	because the client is in a sandbox that the user has not registered
			//	with. We treat it the same as a username/password failure.

			if (dAuthDesc.IsNil())
				{
				SendMessageReplyError(MSG_ERROR_DOES_NOT_EXIST, ERR_INVALID_USERNAME_OR_PASSWORD);
				return false;
				}

			//	If we've failed more than 5 consecutive times, we may need to delay
			//	the next login attempt.

			if ((int)dUserData.GetElement(FIELD_LOGIN_FAILURE_COUNT) > MAX_LOGIN_ATTEMPTS)
				{
				CDateTime LastLoginFailure = dUserData.GetElement(FIELD_LAST_LOGIN_FAILURE_ON);
				CTimeSpan TimeSinceLastFailure = timeSpan(LastLoginFailure, CDateTime(CDateTime::Now));

				//	If it has not been at least 1 hour, we return an error.

				if (TimeSinceLastFailure.Days() == 0 && TimeSinceLastFailure.Seconds() < LOGIN_TIMEOUT)
					{
					//	Timeout

					SendMessageReplyError(MSG_ERROR_DOES_NOT_EXIST, ERR_FAILURE_TIMEOUT);
					return false;
					}
				}

			//	If we have straight credentials, then just compare

			bool bSuccess;
			if (!dCredentials.IsNil())
				bSuccess = ((const CIPInteger &)dCredentials == (const CIPInteger &)dAuthDesc.GetElement(FIELD_CREDENTIALS));

			//	Otherwise, we compare against the challenge

			else if (!dChallengeCredentials.IsNil())
				{
				//	Get the challenge. If not provided then we get it from the user
				//	record.

				CDatum dChallenge = GetOriginalMsg().dPayload.GetElement(2);
				if (dChallenge.IsNil())
					{
					//	Get the expiration time of the challenge

					const CDateTime &Expires = dAuthDesc.GetElement(FIELD_CHALLENGE_EXPIRATION);
					if (Expires < CDateTime(CDateTime::Now))
						{
						SendMessageReplyError(MSG_ERROR_DOES_NOT_EXIST, ERR_INVALID_USERNAME_OR_PASSWORD);
						return false;
						}

					dChallenge = dAuthDesc.GetElement(FIELD_CHALLENGE);
					}

				//	Create a response to the challenge based on the password hash that
				//	we have stored.

				CDatum dCorrectChallenge = CAI1Protocol::CreateSHAPasswordChallengeResponse(
						dAuthDesc.GetElement(FIELD_CREDENTIALS),
						dChallenge
						);

				bSuccess = ((const CIPInteger &)dChallengeCredentials == (const CIPInteger &)dCorrectChallenge);
				}

			//	Otherwise we expect a clear text password

			else if (!dPassword.IsNil())
				{
				//	We have to hash the password to compare with credentials.

				CIPInteger Credentials;
				CCryptosaurInterface::CreateCredentials(dUserData.GetElement(FIELD_USERNAME), dPassword, &Credentials);

				//	Compare

				bSuccess = (Credentials == (const CIPInteger &)dAuthDesc.GetElement(FIELD_CREDENTIALS));
				}
			else
				bSuccess = false;

			//	Success or failure

			if (bSuccess)
				return UpdateLoginSuccess(stateWaitingForCredentials);
			else
				return UpdateLoginFailure();
			}

		//	Can never get here.

		else
			{
			ASSERT(false);
			return false;
			}
		}

	//	Otherwise, if we're waiting for the user record update, then continue

	else if (m_iState == stateWaitingForSuccessUpdate)
		{
		//	Since we succeeded, we send the user sanitized user record back.

		SendMessageReply(MSG_REPLY_DATA, CreateSanitizedUserRecord(Msg.dPayload));
		return false;
		}

	//	If we're waiting for credentials, compose them

	else if (m_iState == stateWaitingForCredentials)
		{
		//	The mutation returns the full record

		CDatum dUserData = Msg.dPayload;

		//	Compute the result

		CComplexStruct *pAuthToken = new CComplexStruct;
		pAuthToken->SetElement(FIELD_USERNAME, dUserData.GetElement(FIELD_USERNAME));
		pAuthToken->SetElement(FIELD_RIGHTS, dUserData.GetElement(FIELD_RIGHTS));
		if (!m_bActual)
			pAuthToken->SetElement(FIELD_SCOPE, m_sScope);

		CDatum dAuthToken = m_pEngine->GenerateAuthToken(CDatum(pAuthToken), m_dwAuthTokenLifetime);

		//	Compose a basic user record

		CComplexStruct *pReply = new CComplexStruct;
		pReply->SetElement(FIELD_AUTH_TOKEN, dAuthToken);
		pReply->SetElement(FIELD_RIGHTS, dUserData.GetElement(FIELD_RIGHTS));
		pReply->SetElement(FIELD_USERNAME, dUserData.GetElement(FIELD_USERNAME));

		//	Send the reply

		SendMessageReply(MSG_REPLY_DATA, CDatum(pReply));

		//	Done

		return false;
		}

	//	Otherwise, failure

	else if (m_iState == stateWaitingForFailureUpdate)
		{
		CDatum dUserData = Msg.dPayload;

		//	If we've exceeded our limit, log it

		int iAttempts = (int)dUserData.GetElement(FIELD_LOGIN_FAILURE_COUNT);
		if (iAttempts > MAX_LOGIN_ATTEMPTS)
			GetProcessCtx()->Log(MSG_LOG_INFO, strPattern(ERR_USERNAME_TIMEOUT, m_sUsername, iAttempts));

		//	Send a failure

		SendMessageReplyError(MSG_ERROR_DOES_NOT_EXIST, ERR_INVALID_USERNAME_OR_PASSWORD);
		return false;
		}

	//	Can never get here

	else
		{
		ASSERT(false);
		return false;
		}
	}
Beispiel #6
0
void CAeonView::Insert (const CTableDimensions &PrimaryDims, CHexeProcess &Process, const CRowKey &PrimaryKey, CDatum dData, CDatum dOldData, SEQUENCENUMBER RowID, bool *retbRecoveryFailed, CString *retsError)

//	Insert
//
//	Insert a row
//
//	NOTE: We cannot fail here because callers should have called CanInsert
//	(above).

	{
	int i;
	CString sError;
	*retbRecoveryFailed = false;

	//	If this is a primary view then all we have to do is insert the row

	if (!IsSecondaryView())
		{
		m_pRows->Insert(PrimaryKey, dData, RowID);
		if (!m_Recovery.Insert(PrimaryKey, dData, RowID, retsError))
			*retbRecoveryFailed = true;
		}

	//	Otherwise, it's more complicated.

	else
		{
		//	If this view is not yet up to date then we skip insertion (we will
		//	insert all rows later).

		if (!IsUpToDate())
			return;

		//	If we are updating an existing row, then we need to remove the old
		//	value. Note that it is OK if OldKey and NewKey end up being the
		//	same; we just end up overwriting it.

		if (!dOldData.IsNil())
			{
			//	Generate a key for the old value. If all key values are non-nil
			//	then we update the old value.

			TArray<CRowKey> OldKeys;
			if (CreateSecondaryKeys(Process, ComputeColumns(Process, dOldData), RowID, &OldKeys))
				{
				//	Now delete the old value (by writing out Nil)

				for (i = 0; i < OldKeys.GetCount(); i++)
					{
					m_pRows->Insert(OldKeys[i], CDatum(), RowID);
					if (!m_Recovery.Insert(OldKeys[i], CDatum(), RowID, retsError))
						*retbRecoveryFailed = true;
					}
				}
			}

		//	Save the new value (only if not Nil)

		if (!dData.IsNil())
			{
			//	Compute columns

			dData = ComputeColumns(Process, dData);

			//	Generate a key for the new value. If all key values are non-nil
			//	then we insert the row into the secondary view.

			TArray<CRowKey> NewKeys;
			if (CreateSecondaryKeys(Process, dData, RowID, &NewKeys))
				{
				//	Generate data for secondary key

				CDatum dViewData;
				CreateSecondaryData(PrimaryDims, PrimaryKey, dData, RowID, &dViewData);

				//	Insert it

				for (i = 0; i < NewKeys.GetCount(); i++)
					{
					m_pRows->Insert(NewKeys[i], dViewData, RowID);
					if (!m_Recovery.Insert(NewKeys[i], dViewData, RowID, retsError))
						*retbRecoveryFailed = true;
					}
				}
			}
		}
	}
Beispiel #7
0
bool CAeonView::InitAsSecondaryView (CDatum dDesc, CHexeProcess &Process, const CString &sRecoveryFilespec, bool bForceUpdate, CString *retsError)

//	InitAsSecondaryView
//
//	Initializes a secondary view.

	{
	int i;

	ASSERT(m_Dims.GetCount() == 0);

	//	Get the name

	m_sName = dDesc.GetElement(FIELD_NAME);

	m_bUsesListKeys = false;

	//	Parse the x dimension

	CDatum dimDesc = dDesc.GetElement(FIELD_X);
	if (!dimDesc.IsNil())
		{
		SDimensionDesc *pDimDesc = m_Dims.Insert();
		CDatum *pKey = m_Keys.Insert();
		if (!CAeonTable::ParseDimensionDescForSecondaryView(dimDesc, Process, pDimDesc, pKey, retsError))
			{
			m_bInvalid = true;
			return false;
			}

		if (pDimDesc->iKeyType == keyListUTF8)
			m_bUsesListKeys = true;

		//	Parse the y dimension

		dimDesc = dDesc.GetElement(FIELD_Y);
		if (!dimDesc.IsNil())
			{
			pDimDesc = m_Dims.Insert();
			pKey = m_Keys.Insert();
			if (!CAeonTable::ParseDimensionDescForSecondaryView(dimDesc, Process, pDimDesc, pKey, retsError))
				{
				m_bInvalid = true;
				return false;
				}

			if (pDimDesc->iKeyType == keyListUTF8)
				m_bUsesListKeys = true;

			//	Parse z dimension

			dimDesc = dDesc.GetElement(FIELD_Z);
			if (!dimDesc.IsNil())
				{
				pDimDesc = m_Dims.Insert();
				pKey = m_Keys.Insert();
				if (!CAeonTable::ParseDimensionDescForSecondaryView(dimDesc, Process, pDimDesc, pKey, retsError))
					{
					m_bInvalid = true;
					return false;
					}

				if (pDimDesc->iKeyType == keyListUTF8)
					m_bUsesListKeys = true;
				}
			}
		}

	//	If we don't have at least one dimension then this is an error

	else
		{
		*retsError = ERR_DIMENSIONS_REQUIRED;
		m_bInvalid = true;
		return false;
		}

	//	Secondary views always have an extra dimension. We use the rowID as a
	//	way to break ties in the other parts of the key (since secondary keys
	//	need not be unique).

	SDimensionDesc *pDimDesc = m_Dims.Insert();
	pDimDesc->iKeyType = keyInt64;
	pDimDesc->iSort = AscendingSort;

	//	Parse columns

	CDatum dColumns = dDesc.GetElement(FIELD_COLUMNS);
	for (i = 0; i < dColumns.GetCount(); i++)
		{
		const CString &sCol = dColumns.GetElement(i);
		if (!sCol.IsEmpty())
			m_Columns.Insert(sCol);
		}

	//	Computed columns

	m_ComputedColumns = dDesc.GetElement(FIELD_COMPUTED_COLUMNS);

	//	We need to set the global environment because it got loaded under a 
	//	different process.

	if (strEquals(m_ComputedColumns.GetTypename(), TYPENAME_HEXE_FUNCTION))
		m_ComputedColumns.SetElement(FIELD_GLOBAL_ENV, Process.GetGlobalEnv());

	//	Exclude nil?

	m_bExcludeNil = !dDesc.GetElement(FIELD_EXCLUDE_NIL_KEYS).IsNil();

	//	Initialize rows

	if (!InitRows(sRecoveryFilespec, NULL, retsError))
		{
		m_bInvalid = true;
		return false;
		}

	//	Set up update. If we have stored an update sequence number then it means
	//	that we are loading an old view that has not yet been fully updated.
	//
	//	Otherwise we take the updating number passed in.

	m_bUpdateNeeded = (bForceUpdate ? true : !dDesc.GetElement(FIELD_UPDATE_NEEDED).IsNil());

	//	Done

	return true;
	}
Beispiel #8
0
bool CAeonView::InitAsPrimaryView (CDatum dDesc, const CString &sRecoveryFilespec, int *retiRowsRecovered, CString *retsError)

//	InitAsPrimaryView
//
//	Initialize from a descriptor

	{
	int i;

	ASSERT(m_Dims.GetCount() == 0);

	//	Parse the x dimension

	CDatum dimDesc = dDesc.GetElement(FIELD_X);
	if (!dimDesc.IsNil())
		{
		SDimensionDesc *pDimDesc = m_Dims.Insert();
		if (!CAeonTable::ParseDimensionDesc(dimDesc, pDimDesc, retsError))
			return false;

		//	Parse the y dimension

		dimDesc = dDesc.GetElement(FIELD_Y);
		if (!dimDesc.IsNil())
			{
			pDimDesc = m_Dims.Insert();
			if (!CAeonTable::ParseDimensionDesc(dimDesc, pDimDesc, retsError))
				return false;

			//	Parse z dimension

			dimDesc = dDesc.GetElement(FIELD_Z);
			if (!dimDesc.IsNil())
				{
				pDimDesc = m_Dims.Insert();
				if (!CAeonTable::ParseDimensionDesc(dimDesc, pDimDesc, retsError))
					return false;
				}
			}
		}

	//	If we don't have at least one dimension then this is an error

	else
		{
		*retsError = ERR_DIMENSIONS_REQUIRED;
		return false;
		}

	//	We do not support list types for primary views (only secondary views)

	for (i = 0; i < m_Dims.GetCount(); i++)
		if (m_Dims[i].iKeyType == keyListUTF8)
			{
			*retsError = ERR_PRIMARY_KEY_CANT_BE_LIST;
			return false;
			}

	//	Initialize rows

	if (!InitRows(sRecoveryFilespec, retiRowsRecovered, retsError))
		return false;

	//	Done

	return true;
	}
Beispiel #9
0
bool CAeonView::CreateSecondaryKeys (CHexeProcess &Process, CDatum dData, SEQUENCENUMBER RowID, TArray<CRowKey> *retKeys)

//	CreateSecondaryKeys
//
//	Creates a secondary key from the data and rowID. We return TRUE if all of 
//	the key values are non-nil. FALSE if one or more values are nil.

	{
	int i;
	bool bAllValid = true;

	//	Pull the dimensions from the data

	TArray<CDatum> KeyData;
	for (i = 0; i < m_Keys.GetCount(); i++)
		{
		CDatum dValue;
		CDatum dKeyDesc = m_Keys[i];

		//	If this is a function then we need to evaluate it.

		if (dKeyDesc.CanInvoke())
			{
			TArray<CDatum> Args;
			Args.Insert(dData);

			CHexeProcess::ERunCodes iRun = Process.Run(dKeyDesc, Args, &dValue);

			switch (iRun)
				{
				case CHexeProcess::runOK:
					//	dValue is a valid value for a key
					break;

				case CHexeProcess::runError:
					dValue = CDatum(strPattern("(%s)", dValue.AsString()));
					break;

				default:
					dValue = CDatum(STR_ERROR_KEY);
				}
			}

		//	Otherwise this specifies a field in the data to use as a key

		else
			dValue = dData.GetElement((const CString &)dKeyDesc);

		//	We don't support Nil keys, so we have to replace these with a
		//	a special value.

		if (dValue.IsNil())
			{
			dValue = CDatum(STR_EMPTY_KEY);

			//	If we're not valid if we're excluding nil keys

			if (m_bExcludeNil)
				bAllValid = false;
			}

		//	Add to list

		KeyData.Insert(dValue);
		}


	//	Generate the keys.
	//	If we use list keys then we need to create permuted keys

	retKeys->DeleteAll();
	if (m_bUsesListKeys)
		CreatePermutedKeys(KeyData, 0, TArray<CDatum>(), RowID, retKeys);

	//	Otherwise we just create the key normally

	else
		{
		CRowKey *pNewKey = retKeys->Insert();
		CRowKey::CreateFromDatumAndRowID(m_Dims, KeyData, RowID, pNewKey);
		}

	//	Done

	return bAllValid;
	}
Beispiel #10
0
void CAeonView::CreatePermutedKeys (const TArray<CDatum> &KeyData, int iDim, const TArray<CDatum> &PrevKey, SEQUENCENUMBER RowID, TArray<CRowKey> *retKeys)

//	CreatePermutedKeys
//
//	Adds keys to retKeys by permuting any list values.

	{
	int i;

	//	If we're done, then add the key

	if (iDim == KeyData.GetCount())
		{
		CRowKey *pNewKey = retKeys->Insert();
		CRowKey::CreateFromDatumAndRowID(m_Dims, PrevKey, RowID, pNewKey);
		}

	//	Otherwise, we generate the keys just for the current dimension and 
	//	recurse.

	else
		{
		switch (m_Dims[iDim].iKeyType)
			{
			//	For list keys, add all the values of the list as separate keys

			case keyListUTF8:
				{
				CDatum dList = KeyData[iDim];

				//	If nil, just add as a single nil key

				if (dList.IsNil())
					{
					TArray<CDatum> NewKey(PrevKey);
					NewKey.Insert(dList);
					CreatePermutedKeys(KeyData, iDim + 1, NewKey, RowID, retKeys);
					}

				//	Otherwise, add all values

				else
					{
					TArray<CDatum> NewKey(PrevKey);
					NewKey.Insert(CDatum());

					for (i = 0; i < dList.GetCount(); i++)
						{
						NewKey[iDim] = dList.GetElement(i);
						CreatePermutedKeys(KeyData, iDim + 1, NewKey, RowID, retKeys);
						}
					}

				break;
				}

			//	For non-list keys we just continue adding them

			default:
				{
				TArray<CDatum> NewKey(PrevKey);
				NewKey.Insert(KeyData[iDim]);
				CreatePermutedKeys(KeyData, iDim + 1, NewKey, RowID, retKeys);
				}
			}
		}
	}
bool CHexeMarkupEvaluator::ProcessResult (SHTTPRequestCtx &Ctx, CHexeProcess::ERunCodes iRun, CDatum dResult)

//	ProcessResult
//
//	Process the result of an evaluation. Returns TRUE if processing should 
//	continue; FALSE if we need RPC or are done processing.

	{
	//	If we have more async calls then return

	if (iRun == CHexeProcess::runAsyncRequest)
		{
		Ctx.iStatus = pstatRPCReady;
		Ctx.sRPCAddr = dResult.GetElement(0);
		Ctx.RPCMsg.sMsg = dResult.GetElement(1);
		Ctx.RPCMsg.dPayload = dResult.GetElement(2);
		Ctx.RPCMsg.dwTicket = 0;
		Ctx.RPCMsg.sReplyAddr = NULL_STR;

		return false;
		}

	//	Otherwise, process the result based on the directive that we're
	//	evaluating.

	bool bResult = true;
	switch (m_iProcessing)
		{
		case tagEval:
			OutputDatum(dResult);
			break;

		case tagFile:
			//	If this is an error, then we return with 404

			if (iRun == CHexeProcess::runError)
				{
				Ctx.iStatus = pstatResponseReady;
				Ctx.Response.InitResponse(http_NOT_FOUND, dResult.AsString());
				bResult = false;
				}

			//	If the result is a list then we expect a fileDesc and fileData.

			else if (dResult.GetCount() >= 2)
				{
				Ctx.iStatus = pstatFileDataReady;
				Ctx.dFileDesc = dResult.GetElement(0);
				Ctx.dFileData = dResult.GetElement(1);
				Ctx.AdditionalHeaders = m_Headers;
				bResult = false;
				}

			//	Otherwise we expect a filePath

			else
				{
				Ctx.iStatus = pstatFilePathReady;
				Ctx.sFilePath = dResult;
				Ctx.AdditionalHeaders = m_Headers;
				bResult = false;
				}
			break;

		case tagHeader:
			bResult = ProcessHeader(Ctx, dResult);
			break;

		case tagIf:
			m_iIfLevel++;
			if (dResult.IsNil())
				m_iIfLevelEnd = m_iIfLevel;
			break;

		case tagRedirect:
			//	If this is an error, then we return with 404

			if (iRun == CHexeProcess::runError)
				{
				Ctx.iStatus = pstatResponseReady;
				Ctx.Response.InitResponse(http_NOT_FOUND, dResult.AsString());
				bResult = false;
				}

			//	Otherwise, we expect a string containing the new address.

			else if (!dResult.IsNil())
				{
				m_dwResponseCode = http_MOVED_PERMANENTLY;
				m_sResponseMsg = STR_MOVED_PERMANENTLY;

				AddHeader(HEADER_LOCATION, dResult);
				}

			break;

		default:
			ASSERT(false);
		}

	m_iProcessing = tagNone;
	return bResult;
	}
Beispiel #12
0
void CAeonEngine::MsgGetRows (const SArchonMessage &Msg, const CHexeSecurityCtx *pSecurityCtx)

//	MsgGetRows
//
//	Aeon.getRows {tableAndView} {key} {count}
//	Aeon.getMoreRows {tableAndView} {lastKey} {count}

	{
	int i;

	CAeonTable *pTable;
	DWORD dwViewID;
	if (!ParseTableAndView(Msg, pSecurityCtx, Msg.dPayload.GetElement(0), &pTable, &dwViewID))
		return;

	//	Get the row limits

	int iRowCount;
	TArray<int> Limits;
	CDatum dLimits = Msg.dPayload.GetElement(2);
	if (dLimits.IsNil())
		iRowCount = -1;
	else if (dLimits.GetCount() <= 1)
		{
		iRowCount = (int)dLimits.GetElement(0);
		if (iRowCount <= 0)
			iRowCount = -1;
		}
	else
		{
		iRowCount = (int)dLimits.GetElement(0);
		if (iRowCount <= 0)
			iRowCount = -1;

		Limits.InsertEmpty(dLimits.GetCount() - 1);
		for (i = 1; i < dLimits.GetCount(); i++)
			Limits[i - 1] = (int)dLimits.GetElement(i);
		}

	//	Set up flags and options

	DWORD dwFlags = 0;
	dwFlags |= (strEquals(Msg.sMsg, MSG_AEON_GET_ROWS) ? 0 : CAeonTable::FLAG_MORE_ROWS);

	CDatum dOptions = Msg.dPayload.GetElement(3);
	for (i = 0; i < dOptions.GetCount(); i++)
		{
		if (strEquals(dOptions.GetElement(i), OPTION_INCLUDE_KEY))
			dwFlags |= CAeonTable::FLAG_INCLUDE_KEY;
		else if (strEquals(dOptions.GetElement(i), OPTION_NO_KEY))
			dwFlags |= CAeonTable::FLAG_NO_KEY;
		else
			{
			SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, strPattern(ERR_INVALID_GET_ROWS_OPTION, Msg.sMsg, dOptions.GetElement(i).AsString()), Msg);
			return;
			}
		}

	//	Ask the table

	CDatum dResult;
	CString sError;
	if (!pTable->GetRows(dwViewID, Msg.dPayload.GetElement(1), iRowCount, Limits, dwFlags, &dResult, &sError))
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, sError, Msg);
		return;
		}

	//	Done

	SendMessageReply(MSG_REPLY_DATA, dResult, Msg);
	}
Beispiel #13
0
void CAeonEngine::MsgFileDownload (const SArchonMessage &Msg, const CHexeSecurityCtx *pSecurityCtx)

//	MsgFileDownload
//
//	Aeon.fileDownload {filePath} [{fileDownloadDesc}]

	{
	CString sError;

	//	Get the filePath

	CString sTable;
	CString sFilePath;
	if (!CAeonTable::ParseFilePath(Msg.dPayload.GetElement(0), &sTable, &sFilePath, &sError))
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, strPattern(STR_ERROR_PARSING_FILE_PATH, sError), Msg);
		return;
		}

	//	Make sure we are allowed access to this table

	if (!ValidateTableAccess(Msg, pSecurityCtx, sTable))
		return;

	//	See if we have a fileDownloadDesc

	CDatum dFileDownloadDesc = Msg.dPayload.GetElement(1);
	int iPartialMaxSize = (dFileDownloadDesc.IsNil() ? -1 : (int)dFileDownloadDesc.GetElement(FIELD_PARTIAL_MAX_SIZE));
	int iPartialPos = (dFileDownloadDesc.IsNil() ? 0 : (int)dFileDownloadDesc.GetElement(FIELD_PARTIAL_POS));
	if (iPartialPos < 0)
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, ERR_INVALID_PARAMETERS, Msg);
		return;
		}

	CDateTime IfModifiedAfter = dFileDownloadDesc.GetElement(FIELD_IF_MODIFIED_AFTER);

	//	Get the table

	CAeonTable *pTable;
	if (!FindTable(sTable, &pTable))
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, strPattern(STR_ERROR_UNKNOWN_TABLE, sTable), Msg);
		return;
		}

#ifdef DEBUG_BLOB_PERF
    DWORD dwStart = ::sysGetTickCount();
#endif

	//	Get the data

	if (!pTable->GetFileData(sFilePath, iPartialMaxSize, iPartialPos, IfModifiedAfter, &dFileDownloadDesc, false, &sError))
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, sError, Msg);
		return;
		}

#ifdef DEBUG_BLOB_PERF
    DWORD dwTime = ::sysGetTicksElapsed(dwStart);
    if (dwTime > 100)
        Log(MSG_LOG_INFO, strPattern("GetFileData %s %D bytes took %D ms.", sFilePath, dFileDownloadDesc.GetElement(FIELD_DATA).GetBinarySize(), dwTime));
#endif

	//	Done

	SendMessageReply(MSG_AEON_FILE_DOWNLOAD_DESC, dFileDownloadDesc, Msg);
	}
Beispiel #14
0
void CAeonEngine::MsgTranspaceDownload (const SArchonMessage &Msg, const CHexeSecurityCtx *pSecurityCtx)

//	MsgTranspaceDownload
//
//	Transpace.download {address} {originalAddress} [{fileDownloadDesc}]

	{
	CString sError;
	CString sAddress = Msg.dPayload.GetElement(0);
	CString sOriginalAddress = Msg.dPayload.GetElement(1);
	CDatum dFileDownloadDesc = Msg.dPayload.GetElement(2);

	//	Parse the address to get the path

	CString sFullPath;
	if (!CTranspaceInterface::ParseAddress(sAddress, NULL, &sFullPath))
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, strPattern(STR_ERROR_PARSING_TRANSPACE_ADDR, sAddress), Msg);
		return;
		}

	//	Get the filePath

	CString sTable;
	CString sFilePath;
	if (!CAeonTable::ParseFilePath(sFullPath, &sTable, &sFilePath, &sError))
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, strPattern(STR_ERROR_PARSING_FILE_PATH, sError), Msg);
		return;
		}

	//	Make sure we are allowed access to this table

	if (!ValidateTableAccess(Msg, pSecurityCtx, sTable))
		return;

	//	See if we have a fileDownloadDesc

	int iPartialMaxSize = (dFileDownloadDesc.IsNil() ? -1 : (int)dFileDownloadDesc.GetElement(FIELD_PARTIAL_MAX_SIZE));
	int iPartialPos = (dFileDownloadDesc.IsNil() ? 0 : (int)dFileDownloadDesc.GetElement(FIELD_PARTIAL_POS));
	if (iPartialPos < 0)
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, ERR_INVALID_PARAMETERS, Msg);
		return;
		}

	CDateTime IfModifiedAfter = dFileDownloadDesc.GetElement(FIELD_IF_MODIFIED_AFTER);

	//	Get the table

	CAeonTable *pTable;
	if (!FindTable(sTable, &pTable))
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, strPattern(STR_ERROR_UNKNOWN_TABLE, sTable), Msg);
		return;
		}

	//	Get the data

	if (!pTable->GetFileData(sFilePath, iPartialMaxSize, iPartialPos, IfModifiedAfter, &dFileDownloadDesc, true, &sError))
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, sError, Msg);
		return;
		}

	//	Add the original address to the download descriptor
	//
	//	NOTE: It is OK to modify this field because we know that GetFileData 
	//	created a new structure.

	dFileDownloadDesc.GetElement(FIELD_FILE_DESC).SetElement(FIELD_ADDRESS, sOriginalAddress);

#ifdef DEBUG_FILES
	Log(MSG_LOG_DEBUG, strPattern("[%x]: Transpace.download address=%s original=%s filePath=%s", Msg.dwTicket, sAddress, sOriginalAddress, sFilePath));
#endif

	//	Done

	SendMessageReply(MSG_AEON_FILE_DOWNLOAD_DESC, dFileDownloadDesc, Msg);
	}