Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,23 @@ public static TokenCredential GetAzureCredential(string? clientId = null)
{
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production";

// CodeQL [SM05139] Okay use of DefaultAzureCredential as it is only used in development
return string.Equals(env, "Development", StringComparison.OrdinalIgnoreCase)
? new DefaultAzureCredential() // CodeQL [SM05139] Okay use of DefaultAzureCredential as it is only used in development
: (clientId != null ? new ManagedIdentityCredential(clientId) : new ManagedIdentityCredential());
if (string.Equals(env, "Development", StringComparison.OrdinalIgnoreCase))
{
// Include ManagedIdentityCredential first so the same image works in AKS
// (where ASPNETCORE_ENVIRONMENT is Development to load appsettings.Development.json
// for the App Configuration endpoint) without falling back to dev-only credentials
// that don't exist inside the pod.
return new ChainedTokenCredential(
clientId != null ? new ManagedIdentityCredential(clientId) : new ManagedIdentityCredential(),
new VisualStudioCredential(),
new AzureCliCredential(),
new AzurePowerShellCredential(),
new AzureDeveloperCliCredential());
}

return clientId != null
? new ManagedIdentityCredential(clientId)
: new ManagedIdentityCredential();
}
}
}
21 changes: 11 additions & 10 deletions App/backend-api/Microsoft.GS.DPS.Host/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,18 @@
UserInterface.AddAPIs(app);

// Inject the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
//{

app.UseSwagger();
app.UseSwaggerUI(options =>
// Swagger UI is enabled only in the Development environment to avoid exposing the
// API surface and schema in production (CodeQL SM04686). Set ASPNETCORE_ENVIRONMENT=Development
// (or use launchSettings.json) to access /swagger locally.
if (app.Environment.IsDevelopment())
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1");
options.RoutePrefix = string.Empty;
});

//}
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1");
options.RoutePrefix = string.Empty;
});
}

app.UseCors("AllowAll");
app.UseHttpsRedirection();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,26 @@ public CosmosDBEntityBase()

/// <summary>
/// Generate partitionkey for CosmosDB
/// using SHA1 hash with id, convert it to uint and divide with number of partitions
/// using SHA256 hash with id, convert it to uint and divide with number of partitions
/// assigned default value as 9999 (9999 partition at this moment)
/// </summary>
Comment thread
Ayaz-Microsoft marked this conversation as resolved.
/// <param name="id"></param>
/// <param name="numberofPartitions"></param>
/// <returns></returns>
public static string GetKey(Guid id, int numberofPartitions)
{
using (var sha1 = SHA1.Create())
{
var hasedVal = sha1.ComputeHash(id.ToByteArray());
var intHashedVal = BitConverter.ToUInt32(hasedVal, 0);
// Use SHA256 instead of SHA1 (SHA1 flagged as broken/weak by SDL).
// This is a *non-cryptographic* use: only the first 4 bytes are consumed to derive a numeric
// partition key. Existing rows already in CosmosDB persist their original __partitionkey field,
// so changing the algorithm only affects partition assignment for newly-created entities.
var hashedVal = SHA256.HashData(id.ToByteArray());
var intHashedVal = BitConverter.ToUInt32(hashedVal, 0);
Comment thread
Ayaz-Microsoft marked this conversation as resolved.

var range = numberofPartitions - 1;
var length = range.ToString().Length;
var range = numberofPartitions - 1;
var length = range.ToString().Length;

var key = (intHashedVal % numberofPartitions).ToString();
return key.PadLeft(length, '0');
}
var key = (intHashedVal % numberofPartitions).ToString();
return key.PadLeft(length, '0');
}
}
}
8 changes: 8 additions & 0 deletions App/frontend-app/public/web.config
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,13 @@
<staticContent>
<mimeMap fileExtension=".json" mimeType="application/json" />
</staticContent>
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="Content-Security-Policy" value="frame-ancestors 'self'" />
<add name="X-Content-Type-Options" value="nosniff" />
<add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
22 changes: 18 additions & 4 deletions App/frontend-app/src/components/chat/chatRoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -574,9 +574,23 @@ export function ChatRoom({ searchResultDocuments, selectedDocuments, chatWithDoc
);
}
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
// Resolve crypto via globalThis so this works in browsers, web workers, and Node.
const c: Crypto | undefined =
typeof globalThis !== 'undefined' ? (globalThis as { crypto?: Crypto }).crypto : undefined;

// Use the cryptographically secure native UUID generator when available.
if (c && typeof c.randomUUID === 'function') {
return c.randomUUID();
}
// Fallback: derive UUIDv4 from cryptographically strong random bytes (no Math.random()).
if (!c || typeof c.getRandomValues !== 'function') {
throw new Error('uuidv4: a secure random number generator (crypto.getRandomValues) is not available in this environment.');
}
const bytes = new Uint8Array(16);
c.getRandomValues(bytes);
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10
const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0'));
return `${hex.slice(0, 4).join('')}-${hex.slice(4, 6).join('')}-${hex.slice(6, 8).join('')}-${hex.slice(8, 10).join('')}-${hex.slice(10, 16).join('')}`;
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,31 @@ interface IPageNumberTabProps {
documentUrl: string | undefined;
}

// Linear, non-backtracking replacement for /^(?:\/\/|[^/]+)*\// (avoids ReDoS).
// Strips an optional "<scheme>://" or leading "//", then everything up to and
// including the next '/' (the host segment). Mirrors the prior regex behavior
// for both absolute (https://host/path) and protocol-relative (//host/path) URLs.
Comment thread
Ayaz-Microsoft marked this conversation as resolved.
Outdated
const stripUrlPrefix = (s: string): string => {
let i = 0;
// Skip optional "<scheme>://" (e.g. https://, http://, ftp://). Anchored,
// bounded character class -> no catastrophic backtracking.
const schemeMatch = /^[a-z][a-z0-9+.-]*:\/\//i.exec(s);
if (schemeMatch) {
i = schemeMatch[0].length;
} else if (s.startsWith("//")) {
i = 2;
}
const slash = s.indexOf("/", i);
return slash === -1 ? s : s.substring(slash + 1);
};

export const PageNumberTab: React.FC<IPageNumberTabProps> = ({ selectedTab, selectedPageMetadata, documentUrl}) => {
if (selectedTab !== "Page Number" || !selectedPageMetadata || !documentUrl) {
return null;
}

const imageUrl = window.ENV.STORAGE_URL +
selectedPageMetadata.document_url.replace(/^(?:\/\/|[^/]+)*\//, "") +
stripUrlPrefix(selectedPageMetadata.document_url) +
"/"

return (
Expand Down
Loading