示例#1
0
int ExecuteScript (const SOptions &Options)
	{
	int i, j;

	//	Load the script file

	CDatum dScript;
	CString sError;
	if (!CDatum::CreateFromFile(Options.sScriptFile, CDatum::formatAEONScript, &dScript, &sError))
		{
		printf("ERROR: %s\n", (LPSTR)sError);
		return 1;
		}

	//	Get the server to connect to

	CString sServer = dScript.GetElement(FIELD_SERVER);
	if (sServer.IsEmpty())
		sServer = Options.sServer;

	//	Connect

	CSocket theSocket;
	if (!ConnectToArcology(STR_ARC_CONSOLE, sServer, Options, &theSocket))
		return 1;

	//	Run the script

	CDatum dCommands = dScript.GetElement(FIELD_COMMANDS);
	for (i = 0; i < dCommands.GetCount(); i++)
		{
		CDatum dCommand = dCommands.GetElement(i);

		//	Generate a command-line from the command

		CStringBuffer Buffer;
		for (j = 0; j < dCommand.GetCount(); j++)
			{
			if (j != 0)
				Buffer.Write(" ", 1);

			dCommand.Serialize(CDatum::formatAEONScript, Buffer);
			}

		//	Run

		printf("%s\n", (LPSTR)(const CString &)Buffer);
		CString sResult = ExecuteArcologyCommand(theSocket, Buffer);
		PrintUTF8(sResult);
		printf("\n");
		}

	//	Done

	return 0;
	}
示例#2
0
CComplexArray::CComplexArray (CDatum dSrc)

//	ComplexArray constructor

	{
	int i;

	if (dSrc.GetBasicType() == CDatum::typeStruct)
		{
		InsertEmpty(1);
		SetElement(0, dSrc);
		}
	else
		{
		int iCount = dSrc.GetCount();

		//	Clone from another complex array

		if (iCount > 0)
			{
			InsertEmpty(iCount);

			for (i = 0; i < iCount; i++)
				SetElement(i, dSrc.GetElement(i));
			}
		}
	}
示例#3
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);
	}
示例#4
0
bool IComplexDatum::DeserializeAEONScript (CDatum::ESerializationFormats iFormat, const CString &sTypename, CCharStream *pStream)

//	DeserializeAEONScript
//
//	Deserialize AEONScript

	{
	int i;
	DWORD dwFlags = OnGetSerializeFlags();

	//	If we have an open brace then we've stored everything as a structure.

	if (pStream->GetChar() == '{')
		{
		//	Object must support this

		if (!(dwFlags & FLAG_SERIALIZE_AS_STRUCT))
			return false;

		//	Parse the structure

		CAEONScriptParser Parser(pStream);
		CDatum dData;
		CAEONScriptParser::ETokens iToken = Parser.ParseToken(&dData);
		if (iToken != CAEONScriptParser::tkDatum)
			return false;

		//	Take all the fields in the structure and apply them to our object
		//	(our descendants will do the right thing).

		for (i = 0; i < dData.GetCount(); i++)
			SetElement(dData.GetKey(i), dData.GetElement(i));
		}

	//	Otherwise we expect base64 encoded data

	else
		{
		//	Backup one character because we want the OnDeserialize call to read it.

		pStream->UnreadChar();

		//	Deserialize

		CBase64Decoder Decoder(pStream->GetByteStream());
		if (!OnDeserialize(iFormat, sTypename, Decoder))
			return false;

		//	Read the next character into the stream 

		pStream->RefreshStream();
		pStream->ReadChar();
		}

	return true;
	}
示例#5
0
CComplexStruct::CComplexStruct (CDatum dSrc)

//	CComplexStruct constructor

	{
	//	Clone from another complex structure

	for (int i = 0; i < dSrc.GetCount(); i++)
		{
		CString sKey = dSrc.GetKey(i);
		if (!sKey.IsEmpty())
			SetElement(sKey, dSrc.GetElement(i));
		}
	}
示例#6
0
void CComplexStruct::AppendStruct (CDatum dDatum)

//	AppendStruct
//
//	Appends the element of the given structure

	{
	int i;

	if (dDatum.GetBasicType() == CDatum::typeStruct)
		{
		for (i = 0; i < dDatum.GetCount(); i++)
			SetElement(dDatum.GetKey(i), dDatum.GetElement(i));
		}
	}
void CHexeMarkupEvaluator::OutputDatum (CDatum dValue)

//	OutputDatum
//
//	Outputs a datum to the resulting HTML page. NOTE: We expect the values to be
//	HTML compatible (i.e., caller is responsible for escaping).

	{
	int i;

	if (dValue.GetBasicType() == CDatum::typeArray)
		{
		for (i = 0; i < dValue.GetCount(); i++)
			OutputDatum(dValue.GetElement(i));
		}
	else
		{
		m_Output.Write(dValue.AsString());
		}
	}
示例#8
0
CDatum CUserInfoSession::CreateSanitizedUserRecord (CDatum dRecord)

//	CreateSanitizedUserRecord
//
//	Creates a user record suitable for returning to clients. In partincular,
//	we remove the authentication information.

	{
	int i;

	//	Create a destination

	CComplexStruct *pDest = new CComplexStruct;

	//	Copy all appropriate fields

	for (i = 0; i < dRecord.GetCount(); i++)
		{
		//	If this is an auth field, then skip it

		if (strEquals(dRecord.GetKey(i), FIELD_AUTH_DESC))
			;

		else if (strEndsWith(dRecord.GetKey(i), FIELD_AUTH_DESC_SUFFIX))
			;
		
		//	Otherwise, copy it

		else
			pDest->SetElement(dRecord.GetKey(i), dRecord.GetElement(i));
		}

	//	Done

	return CDatum(pDest);
	}
示例#9
0
CString ExecuteUpgrade (CSocket &theSocket, const CString &sCmd)
	{
	int i;

	CString sRoot = fileGetPath(fileGetExecutableFilespec());

	//	Make a list of all executable files to upgrade

	TArray<CString> FileList;
	if (!fileGetFileList(sRoot, NULL_STR, CString("*.exe"), FFL_FLAG_RELATIVE_FILESPEC, &FileList))
		return CString("ERROR: Unable to obtain a list of executable files to upgrade.");

	//	Prepare a request upgrade command

	CStringBuffer Output;
	Output.Write("requestUpgrade (", 16);

	for (i = 0; i < FileList.GetCount(); i++)
		{
		CString sFilespec = fileAppend(sRoot, FileList[i]);

		//	Version

		SFileVersionInfo Info;
		if (!fileGetVersionInfo(sFilespec, &Info))
			{
			printf("ERROR: Unable to get file version: %s\n", (LPSTR)sFilespec);
			continue;
			}

		CIPInteger Version(Info.dwProductVersion);
		CString sVersion = Version.AsString();

		//	Checksum

		DWORD dwChecksum = fileChecksumAdler32(sFilespec);
		if (dwChecksum == 0)
			{
			printf("ERROR: Unable to get file checksum: %s\n", (LPSTR)sFilespec);
			continue;
			}

		CString sOutput = strPattern("{filename:\"%s\" version:%s checksum:%d} ", FileList[i], sVersion, dwChecksum);
		Output.Write(sOutput);
		}

	Output.Write(")", 1);

	//	Send the command

	CString sSend = CString::CreateFromHandoff(Output);
	CString sResult;
	CDatum dResult;
	ExecuteArcologyCommand(theSocket, sSend, &sResult, &dResult);
	if (strEquals(sResult, CString("ERROR")))
		return dResult.AsString();

	//	Show all the files to upgrade

	CDatum dUpgradeDesc = dResult.GetElement(0).GetElement(FIELD_UPGRADE_DESC);
	for (i = 0; i < dUpgradeDesc.GetCount(); i++)
		{
		CDatum dFileDesc = dUpgradeDesc.GetElement(i);

		printf("Upgrading %s\n", (LPSTR)dFileDesc.GetElement(FIELD_FILENAME).AsString());
		}

	//	Confirm

	CString sConfirm = GetInputLine(CString("\nAre you sure you want to upgrade the arcology? [y/n] : "));
	if (*sConfirm.GetParsePointer() != 'y' && *sConfirm.GetParsePointer() != 'Y')
		return NULL_STR;

	//	Upload the new files.

	for (i = 0; i < dUpgradeDesc.GetCount(); i++)
		{
		CDatum dFileDesc = dUpgradeDesc.GetElement(i);
		const CString &sFilename = dFileDesc.GetElement(FIELD_FILENAME);
		CString sFilespec = fileAppend(sRoot, sFilename);

		CString sResult = UploadFile(theSocket, CMD_UPLOAD_UPGRADE, sFilename, sFilespec);
		printf("%s\n", (LPSTR)sResult);
		}

	//	Complete the upgrade

	return ExecuteArcologyCommand(theSocket, CMD_COMPLETE_UPGRADE);
	}
示例#10
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;
	}
示例#11
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);
				}
			}
		}
	}
示例#12
0
bool CAeonEngine::ParseTableAndView (const SArchonMessage &Msg, 
									 const CHexeSecurityCtx *pSecurityCtx, 
									 CDatum dTableAndView, 
									 CAeonTable **retpTable, 
									 DWORD *retdwViewID,
									 CDatum dKey,
									 CRowKey *retKey)

//	ParseTableAndView
//
//	Parses a datum as follows:
//
//	If a single string, it specifies a table and the default view.
//	If an array with two strings, the first is the table name; the second is the view name.

	{
	CString sError;

	//	If we're not ready, then error

	if (!m_bReady)
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, ERR_NOT_READY, Msg);
		return false;
		}

	//	Parse the table names

	CString sTable;
	CString sView;

	if (dTableAndView.GetCount() < 2)
		sTable = dTableAndView.AsString();
	else
		{
		sTable = dTableAndView.GetElement(0).AsString();
		sView = dTableAndView.GetElement(1).AsString();
		}

	//	Make sure we have access

	if (pSecurityCtx && !pSecurityCtx->IsNamespaceAccessible(sTable))
		{
		SendMessageReplyError(MSG_ERROR_NOT_ALLOWED, strPattern(ERR_NOT_IN_SANDBOX, sTable, pSecurityCtx->GetSandboxName()), Msg);
		return false;
		}

	//	Get the table

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

	//	Get the view. If we want a key, take this opportunity to parse it.

	DWORD dwViewID;
	if (retKey)
		{
		if (!pTable->FindViewAndPath(sView, &dwViewID, dKey, retKey, &sError))
			{
			SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, sError, Msg);
			return false;
			}
		}

	//	Otherwise just get the view.

	else
		{
		if (!pTable->FindView(sView, &dwViewID))
			{
			SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY,  strPattern(ERR_UNKNOWN_VIEW, sTable, sView), Msg);
			return false;
			}
		}

	//	Done

	if (retpTable)
		*retpTable = pTable;

	if (retdwViewID)
		*retdwViewID = dwViewID;

	return true;
	}
示例#13
0
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;
	}
示例#14
0
int CDatum::DefaultCompare (void *pCtx, const CDatum &dKey1, const CDatum &dKey2)

//	DefaultCompare
//
//	Default comparison routine used for sorting. Returns:
//
//	-1:		If dKey1 < dKey2
//	0:		If dKey1 == dKey2
//	1:		If dKey1 > dKey2
//
//	NOTES:
//
//	Nil == ""
//	Nil == {}
//	Nil == ()
//	"abc" != "ABC"

	{
	int i;

	//	If both are the same datatype, then compare

	CDatum::Types iType1 = dKey1.GetBasicType();
	CDatum::Types iType2 = dKey2.GetBasicType();

	//	If both types are equal, then compare

	if (iType1 == iType2)
		{
		switch (iType1)
			{
			case CDatum::typeNil:
			case CDatum::typeTrue:
				return 0;

			case CDatum::typeInteger32:
				if ((int)dKey1 > (int)dKey2)
					return 1;
				else if ((int)dKey1 < (int)dKey2)
					return -1;
				else
					return 0;

			case CDatum::typeInteger64:
				if ((DWORDLONG)dKey1 > (DWORDLONG)dKey2)
					return 1;
				else if ((DWORDLONG)dKey1 < (DWORDLONG)dKey2)
					return -1;
				else
					return 0;

			case CDatum::typeDouble:
				if ((double)dKey1 > (double)dKey2)
					return 1;
				else if ((double)dKey1 < (double)dKey2)
					return -1;
				else
					return 0;

			case CDatum::typeIntegerIP:
				return KeyCompare((const CIPInteger &)dKey1, (const CIPInteger &)dKey2);

			case CDatum::typeString:
				return KeyCompare((const CString &)dKey1, (const CString &)dKey2);

			case CDatum::typeDateTime:
				return ((const CDateTime &)dKey1).Compare((const CDateTime &)dKey2);

			case CDatum::typeArray:
				if (dKey1.GetCount() > dKey2.GetCount())
					return 1;
				else if (dKey1.GetCount() < dKey2.GetCount())
					return -1;
				else
					{
					for (i = 0; i < dKey1.GetCount(); i++)
						{
						CDatum dItem1 = dKey1.GetElement(i);
						CDatum dItem2 = dKey2.GetElement(i);
						int iItemCompare = CDatum::DefaultCompare(pCtx, dItem1, dItem2);
						if (iItemCompare != 0)
							return iItemCompare;
						}

					return 0;
					}

			case CDatum::typeStruct:
				if (dKey1.GetCount() > dKey2.GetCount())
					return 1;
				else if (dKey1.GetCount() < dKey2.GetCount())
					return -1;
				else
					{
					for (i = 0; i < dKey1.GetCount(); i++)
						{
						CString sItemKey1 = dKey1.GetKey(i);
						CString sItemKey2 = dKey2.GetKey(i);
						int iKeyCompare = KeyCompare(sItemKey1, sItemKey2);
						if (iKeyCompare != 0)
							return iKeyCompare;

						CDatum dItem1 = dKey1.GetElement(i);
						CDatum dItem2 = dKey2.GetElement(i);
						int iItemCompare = CDatum::DefaultCompare(pCtx, dItem1, dItem2);
						if (iItemCompare != 0)
							return iItemCompare;
						}

					return 0;
					}

			//	LATER: Not yet supported

			default:
				return 0;
			}
		}

	//	If one of the types is nil, then compare

	else if (iType1 == CDatum::typeNil || iType2 == CDatum::typeNil)
		{
		CDatum dNonNil;
		int iResult;
		if (iType2 == CDatum::typeNil)
			{
			dNonNil = dKey1;
			Swap(iType1, iType2);
			iResult = 1;
			}
		else
			{
			dNonNil = dKey2;
			iResult = -1;
			}

		switch (iType2)
			{
			case CDatum::typeString:
				if (((const CString &)dNonNil).IsEmpty())
					return 0;
				else
					return iResult;

			case CDatum::typeArray:
			case CDatum::typeStruct:
				if (dNonNil.GetCount() == 0)
					return 0;
				else
					return iResult;

			default:
				//	nil is always less
				return iResult;
			}
		}

	//	If one of the types is a number, then compare as numbers

	else if (dKey1.IsNumber() || dKey2.IsNumber())
		{
		CNumberValue Number1(dKey1);
		CNumberValue Number2(dKey2);

		if (Number1.IsValidNumber() && Number2.IsValidNumber())
			return Number1.Compare(Number2);
		else if (Number1.IsValidNumber())
			return 1;
		else if (Number2.IsValidNumber())
			return -1;
		else
			return 0;
		}

	//	Otherwise, cannot compare

	else
		return 0;
	}
示例#15
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);
	}
示例#16
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;
		}
	}
示例#17
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;
	}
示例#18
0
void CAeonEngine::MsgOnMnemosynthModified (const SArchonMessage &Msg, const CHexeSecurityCtx *pSecurityCtx)

//	MsgOnMnemosynthModified
//
//	Mnemosynth.onModified {updates}

	{
	int i;

	//	If we haven't yet started we don't care about this message.

	if (!m_bMachineStarted)
		return;

	//	Get the updates

	CDatum dCollections = Msg.dPayload.GetElement(FIELD_COLLECTIONS);
	CDatum dEntries = Msg.dPayload.GetElement(FIELD_ENTRIES);

	//	See what changed

	bool bStorageChanged = false;
	for (i = 0; i < dEntries.GetCount(); i++)
		{
		CDatum dEntry = dEntries.GetElement(i);

		const CString &sCollection = dCollections.GetElement((int)dEntry.GetElement(0));
		if (strEquals(sCollection, MNEMO_ARC_STORAGE))
			bStorageChanged = true;
		}

	//	If storage changed then update local storage (which will tell us what
	//	storage was added or deleted).

	if (bStorageChanged)
		{
		CSmartLock Lock(m_cs);

		CString sError;
		TArray<CString> VolumesAdded;
		TArray<CString> VolumesDeleted;
		if (!m_LocalVolumes.Reinit(GetProcessCtx(), &VolumesAdded, &VolumesDeleted, &sError))
			{
			//	LATER: We don't know how to recover from this, so we should go into
			//	safe mode.
			Log(MSG_LOG_ERROR, sError);
			return;
			}

		//	Tell every table that volumes were added and deleted so that they can
		//	change their primary and backup volumes.

		if (VolumesAdded.GetCount() > 0 || VolumesDeleted.GetCount() > 0)
			{
			for (i = 0; i < m_Tables.GetCount(); i++)
				m_Tables[i]->OnVolumesChanged(VolumesDeleted);

			//	LATER: See if there are any existing tables in the new volume.
			}
		}
	}