Merged PR 935: added container and blob sas tokens

added container and blob sas tokens

Related work items: #7948
This commit is contained in:
Robert Bond
2022-10-25 13:03:22 +00:00
3 changed files with 168 additions and 116 deletions
+148 -116
View File
@@ -1,15 +1,115 @@
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import { BlobServiceClient, ContainerClient } from "@azure/storage-blob";
import { import {
DefaultAzureCredential, ContainerClient,
InteractiveBrowserCredential, BlockBlobClient,
EnvironmentCredential, BlobServiceClient,
ClientSecretCredential, BlobSASPermissions,
} from "@azure/identity"; ContainerSASPermissions,
import { consoleLogger, hashAPIPath } from "."; generateBlobSASQueryParameters,
SASProtocol,
} from "@azure/storage-blob";
import { DefaultAzureCredential } from "@azure/identity";
import { consoleLogger, conLog, hashAPIPath } from ".";
import _ from "lodash"; import _ from "lodash";
const STORAGE_PATH = process.env.AZURE_PEDW_STORAGE_ENDPOINT; const STORAGE_PATH = process.env.AZURE_PEDW_STORAGE_ENDPOINT;
const STORAGE_CONTAINER = process.env.AZURE_PEDW_CONTAINER; const STORAGE_CONTAINER = process.env.AZURE_PEDW_CONTAINER;
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
export const createContainerSas = async (containerName) => {
// Get environment variables
// Best practice: create time limits
const TEN_MINUTES = 10 * 60 * 1000;
const NOW = new Date();
// Best practice: set start time a little before current time to
// make sure any clock issues are avoided
const TEN_MINUTES_BEFORE_NOW = new Date(NOW.valueOf() - TEN_MINUTES);
const TEN_MINUTES_AFTER_NOW = new Date(NOW.valueOf() + TEN_MINUTES);
// Best practice: use managed identity - DefaultAzureCredential
const blobServiceClient = new BlobServiceClient(
`${STORAGE_PATH}`,
new DefaultAzureCredential()
);
// Best practice: delegation key is time-limited
// When using a user delegation key, container must already exist
const userDelegationKey = await blobServiceClient.getUserDelegationKey(
TEN_MINUTES_BEFORE_NOW,
TEN_MINUTES_AFTER_NOW
);
// Need only list permission to list blobs
const containerPermissions = "rcwltd";
// Best practice: SAS options are time-limited
const sasOptions = {
containerName,
permissions: ContainerSASPermissions.parse(containerPermissions),
protocol: SASProtocol.HttpsAndHttp,
startsOn: TEN_MINUTES_BEFORE_NOW,
expiresOn: TEN_MINUTES_AFTER_NOW,
};
//conLogJSON.stringify(sasOptions));
const sasToken = generateBlobSASQueryParameters(
sasOptions,
userDelegationKey,
accountName
).toString();
return sasToken;
};
export const createBlobSas = async (containerName, blobName) => {
// Get environment variables
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
// Best practice: create time limits
const TEN_MINUTES = 10 * 60 * 1000;
const NOW = new Date();
// Best practice: set start time a little before current time to
// make sure any clock issues are avoided
const TEN_MINUTES_BEFORE_NOW = new Date(NOW.valueOf() - TEN_MINUTES);
const TEN_MINUTES_AFTER_NOW = new Date(NOW.valueOf() + TEN_MINUTES);
// Best practice: use managed identity - DefaultAzureCredential
const blobServiceClient = new BlobServiceClient(
`https://${accountName}.blob.core.windows.net`,
new DefaultAzureCredential()
);
// Best practice: delegation key is time-limited
// When using a user delegation key, container must already exist
const userDelegationKey = await blobServiceClient.getUserDelegationKey(
TEN_MINUTES_BEFORE_NOW,
TEN_MINUTES_AFTER_NOW
);
// Need only create/write permission to upload file
const blobPermissionsForAnonymousUser = "rcwt";
// Best practice: SAS options are time-limited
const sasOptions = {
blobName,
containerName,
permissions: BlobSASPermissions.parse(blobPermissionsForAnonymousUser),
protocol: SASProtocol.HttpsAndHttp,
startsOn: TEN_MINUTES_BEFORE_NOW,
expiresOn: TEN_MINUTES_AFTER_NOW,
};
const sasToken = generateBlobSASQueryParameters(
sasOptions,
userDelegationKey,
accountName
).toString();
return sasToken;
};
export const createContainer = async (containerName) => { export const createContainer = async (containerName) => {
const creds = new DefaultAzureCredential(); const creds = new DefaultAzureCredential();
@@ -30,15 +130,6 @@ export const createContainer = async (containerName) => {
const blobServiceClient = new BlobServiceClient(`${STORAGE_PATH}`, creds); const blobServiceClient = new BlobServiceClient(`${STORAGE_PATH}`, creds);
const createContainerResponse = await containerClient.createIfNotExists(); const createContainerResponse = await containerClient.createIfNotExists();
// console.log(
// `Created container ${containerName} successfully`,
// createContainerResponse.requestId
// );
// console.log("Containers:");
// for await (const container of blobServiceClient.listContainers()) {
// console.log(`- ${container.name}`);
// }
console.log( console.log(
"\n//////////////////\n container name :", "\n//////////////////\n container name :",
@@ -60,14 +151,11 @@ export const getContainers = async () => {
}; };
export const getBlobs = async (containerName, casefolderID) => { export const getBlobs = async (containerName, casefolderID) => {
const creds = new DefaultAzureCredential(); const containerToken = await createContainerSas(containerName);
const sasUrl = `${STORAGE_PATH}/${containerName}?${containerToken}`;
const containerClient = new ContainerClient(sasUrl);
const containerClient = new ContainerClient( //conLog"getBlobs " + sasUrl);
`${STORAGE_PATH}/${containerName}`,
creds
);
containerClient.createIfNotExists();
const blobObj = []; const blobObj = [];
for await (const blob of containerClient.listBlobsFlat({ for await (const blob of containerClient.listBlobsFlat({
@@ -131,12 +219,9 @@ export const getBlobs = async (containerName, casefolderID) => {
}; };
export const createBlob = async (formContent, containerName, caseref) => { export const createBlob = async (formContent, containerName, caseref) => {
const creds = new DefaultAzureCredential(); const containerToken = await createContainerSas(containerName);
const sasUrl = `${STORAGE_PATH}/${containerName}?${containerToken}`;
const containerClient = new ContainerClient( const containerClient = new ContainerClient(sasUrl);
`${STORAGE_PATH}/${containerName}`,
creds
);
formContent = JSON.parse(formContent); formContent = JSON.parse(formContent);
let caseID = formContent.pinswg_name; let caseID = formContent.pinswg_name;
@@ -161,14 +246,13 @@ export const deleteBlob = async (containerName, blobName) => {
deleteSnapshots: "include", // or 'only' deleteSnapshots: "include", // or 'only'
}; };
const containerClient = new ContainerClient( const containerToken = await createContainerSas(containerName);
`${STORAGE_PATH}/${containerName.toLowerCase()}`, const sasUrl = `${STORAGE_PATH}/${containerName}?${containerToken}`;
creds const containerClient = new ContainerClient(sasUrl);
);
const blockBlobClient = containerClient.getBlockBlobClient(blobName); const blockBlobClient = containerClient.getBlockBlobClient(blobName);
await blockBlobClient.deleteIfExists(options); await blockBlobClient.delete(options);
console.log(`deleted blob ${blobName}`); console.log(`deleted blob ${blobName}`);
@@ -182,10 +266,11 @@ export const deleteBlobCase = async (containerName, blobName) => {
deleteSnapshots: "include", // or 'only' deleteSnapshots: "include", // or 'only'
}; };
const containerClient = new ContainerClient( const containerToken = await createContainerSas(containerName);
`${STORAGE_PATH}/${containerName}`, const sasUrl = `${STORAGE_PATH}/${containerName}?${containerToken}`;
creds const containerClient = new ContainerClient(sasUrl);
);
//conLog"deleteBlobCase ");
console.log("blob to delete:", blobName); console.log("blob to delete:", blobName);
@@ -205,12 +290,9 @@ export const deleteBlobCase = async (containerName, blobName) => {
}; };
export const uploadFile = async (formContent, containerName, foldername) => { export const uploadFile = async (formContent, containerName, foldername) => {
const creds = new DefaultAzureCredential(); const containerToken = await createContainerSas(containerName);
const sasUrl = `${STORAGE_PATH}/${containerName}?${containerToken}`;
const containerClient = new ContainerClient( const containerClient = new ContainerClient(sasUrl);
`${STORAGE_PATH}/${containerName}`,
creds
);
const files = formContent; const files = formContent;
@@ -236,13 +318,9 @@ export const uploadFile = async (formContent, containerName, foldername) => {
export const downloadFile = async (containerName, blobName) => { export const downloadFile = async (containerName, blobName) => {
//console.log.apply(containerName, blobName); //console.log.apply(containerName, blobName);
const creds = new DefaultAzureCredential(); const containerToken = await createContainerSas(containerName);
const sasUrl = `${STORAGE_PATH}/${containerName}?${containerToken}`;
const containerClient = new ContainerClient( const containerClient = new ContainerClient(sasUrl);
`${STORAGE_PATH}/${containerName}`,
creds
);
const blobClient = containerClient.getBlobClient(blobName); const blobClient = containerClient.getBlobClient(blobName);
const downloadedBlob = await blobClient.download(0); const downloadedBlob = await blobClient.download(0);
@@ -256,13 +334,10 @@ export const downloadProgressFile = async (
casefolderID casefolderID
) => { ) => {
//console.log.apply(containerName, blobName); //console.log.apply(containerName, blobName);
const creds = new DefaultAzureCredential();
const containerClient = new ContainerClient(
`${STORAGE_PATH}/${containerName}`,
creds
);
const containerToken = await createContainerSas(containerName);
const sasUrl = `${STORAGE_PATH}/${containerName}?${containerToken}`;
const containerClient = new ContainerClient(sasUrl);
const blobClient = containerClient.getBlobClient(blobName); const blobClient = containerClient.getBlobClient(blobName);
const downloadedBlob = await blobClient.download(0); const downloadedBlob = await blobClient.download(0);
@@ -276,15 +351,13 @@ export const downloadAllProgressFiles = async (
) => { ) => {
console.log( console.log(
"/////////////////////////\n downloading files: " + "/////////////////////////\n downloading files: " +
progressBlobObj + JSON.stringify(progressBlobObj) +
"\n/////////////////////////\n" "\n/////////////////////////\n"
); );
const creds = new DefaultAzureCredential();
const containerClient = new ContainerClient( const containerToken = await createContainerSas(containerName);
`${STORAGE_PATH}/${containerName}`, const sasUrl = `${STORAGE_PATH}/${containerName}?${containerToken}`;
creds const containerClient = new ContainerClient(sasUrl);
);
let blobClient = {}; let blobClient = {};
let downloadedBlob = {}; let downloadedBlob = {};
@@ -349,45 +422,28 @@ export const getCaseBlob = async (
caseReference, caseReference,
formContent formContent
) => { ) => {
const creds = new DefaultAzureCredential();
const containerClient = new ContainerClient(
`${STORAGE_PATH}/${containerName}`,
creds
);
containerClient.createIfNotExists();
let blobCount = 0;
for await (const blob of containerClient.listBlobsFlat({
prefix: caseReference,
})) {
blobCount++;
}
const content = JSON.stringify(formContent); const content = JSON.stringify(formContent);
const blobName = caseReference + "/case/" + caseReference + "_case.json"; const blobName = caseReference + "/case/" + caseReference + "_case.json";
console.log("blobName:", blobName); const containerBlobToken = await createBlobSas(containerName, blobName);
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const blobSasUrl = `${STORAGE_PATH}/${containerName}/${blobName}?${containerBlobToken}`;
const blockBlobClient = new BlockBlobClient(blobSasUrl);
const uploadBlobResponse = await blockBlobClient.upload( const uploadBlobResponse = await blockBlobClient.upload(
content, content,
Buffer.byteLength(content) Buffer.byteLength(content)
); );
return blobName; return blobName;
}; };
export const getProgressBlobs = async (containerName, caseReference) => { export const getProgressBlobs = async (containerName, caseReference) => {
const creds = new DefaultAzureCredential(); const containerToken = await createContainerSas(containerName);
const containerClient = new ContainerClient( const sasUrl = `${STORAGE_PATH}/${containerName}?${containerToken}`;
`${STORAGE_PATH}/${containerName}`,
creds
);
containerClient.createIfNotExists(); const containerClient = new ContainerClient(sasUrl);
let blobCount = 0; let blobCount = 0;
for await (const blob of containerClient.listBlobsFlat({ for await (const blob of containerClient.listBlobsFlat({
@@ -449,28 +505,16 @@ export const getProgressBlobs = async (containerName, caseReference) => {
}; };
export const getAllProgressBlobs = async (containerName) => { export const getAllProgressBlobs = async (containerName) => {
const creds = new DefaultAzureCredential(); const containerToken = await createContainerSas(containerName);
const containerClient = new ContainerClient( const sasUrl = `${STORAGE_PATH}/${containerName}?${containerToken}`;
`${STORAGE_PATH}/${containerName}`,
creds
);
containerClient.createIfNotExists(); const containerClient = new ContainerClient(sasUrl);
let blobCount = 0; let blobCount = 0;
for await (const blob of containerClient.listBlobsFlat({
// prefix: caseReference,
})) {
blobCount++;
}
console.log("this is the caasefolder:", blobCount);
let blobObj = []; let blobObj = [];
for await (const blob of containerClient.listBlobsFlat({ for await (const blob of containerClient.listBlobsFlat()) {
//prefix: caseReference + "/" + caseReference + ".json",
})) {
blob.name.split("/")[1].indexOf(".json") > 0 && blob.name.split("/")[1].indexOf(".json") > 0 &&
blob.name.split("/")[1].indexOf("undefined") < 0 && blob.name.split("/")[1].indexOf("undefined") < 0 &&
blobObj.push({ blobObj.push({
@@ -486,18 +530,6 @@ export const getAllProgressBlobs = async (containerName) => {
"contentLength": blob.properties.contentLength, "contentLength": blob.properties.contentLength,
"contentType": blob.contentType, "contentType": blob.contentType,
"lastModified": blob.properties.lastModified, "lastModified": blob.properties.lastModified,
// "hashedfilepath": hashAPIPath(
// "/api/file/downloadblob?container=" +
// containerName +
// ),
// "hasheddeletepath": hashAPIPath(
// "/api/file/deleteblob?container=" +
// containerName +
// ),
// "hashgetblobs": hashAPIPath(
// "/api/file/getbloblist?container=" +
// containerName +
// ),
}); });
} }
+11
View File
@@ -40,6 +40,17 @@ export const consoleLogger = (err) => {
return errStr; return errStr;
}; };
export const conLog = (err) => {
var errStr =
"\n\n/////////////////////////////////////////////////\nResponse: " +
"\n" +
err +
"\n/////////////////////////////////////////////////\n\n";
console.log(errStr);
return errStr;
};
export const getToken = () => { export const getToken = () => {
return axios return axios
.post( .post(
+9
View File
@@ -276,6 +276,15 @@ const CaseSummary = (props) => {
</dl> </dl>
</div> </div>
</div> </div>
{/* {_.has(detailsObj, "pinswg_startdatetimeiftheevent") &&
detailsObj.pinswg_startdatetimeiftheevent}
{_.has(detailsObj, "pinswg_startdateoftheevent") &&
detailsObj.pinswg_startdateoftheevent}
{_.has(detailsObj, "pinswg_startdateofevent") &&
detailsObj.pinswg_startdateofevent}
{_.has(detailsObj, "pinswg_starttimeoftheevent") &&
detailsObj.pinswg_starttimeoftheevent} */}
{/* <div className="govuk-grid-row"> {/* <div className="govuk-grid-row">
<div className="govuk-grid-column-full"> <div className="govuk-grid-column-full">
<div className="govuk-button-group"> <div className="govuk-button-group">