-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#175072065] EXPERIMENTAL: Start io-backend as Azure Function #722
base: master
Are you sure you want to change the base?
Changes from 3 commits
93c5691
8a8e8ae
9a5bd62
67816b2
8028b3d
fa0147d
70bc538
f59c56d
e641ee7
94282ce
4a6d18a
6a7a1d8
07f66d5
95de2e8
a13fdeb
26ccedf
2e70348
2ddafb0
d2316d8
480050e
4c11a09
7ec83a1
61cb35a
a4fb41a
3ae06ab
7dba4e6
52ee814
08e37de
0f5a573
d4cf44a
972ede7
d7312f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
*.js.map | ||
*.ts | ||
.git* | ||
.vscode* | ||
.circleci* | ||
.prettierrc | ||
local.settings.json* | ||
tsconfig.json | ||
tslint.json | ||
README.md | ||
yarn.lock | ||
jest.config.js | ||
__* | ||
Dangerfile.js | ||
CODEOWNERS |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"bindings": [ | ||
{ | ||
"authLevel": "anonymous", | ||
"type": "httpTrigger", | ||
"direction": "in", | ||
"name": "req", | ||
"route": "{*segments}", | ||
"methods": [ | ||
"get", | ||
"post", | ||
"put", | ||
"patch", | ||
"delete" | ||
] | ||
}, | ||
{ | ||
"type": "http", | ||
"direction": "out", | ||
"name": "res" | ||
} | ||
], | ||
"scriptFile": "./index.js" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import * as winston from "winston"; | ||
|
||
import { Context } from "@azure/functions"; | ||
import { secureExpressApp } from "io-functions-commons/dist/src/utils/express"; | ||
import { AzureContextTransport } from "io-functions-commons/dist/src/utils/logging"; | ||
import { setAppContext } from "io-functions-commons/dist/src/utils/middlewares/context_middleware"; | ||
import createAzureFunctionHandler from "io-functions-express/dist/src/createAzureFunctionsHandler"; | ||
|
||
/** | ||
* Main entry point for the Digital Citizenship proxy. | ||
*/ | ||
|
||
import { fromNullable } from "fp-ts/lib/Option"; | ||
import { newApp } from "../src/app"; | ||
import { | ||
ALLOW_BPD_IP_SOURCE_RANGE, | ||
ALLOW_MYPORTAL_IP_SOURCE_RANGE, | ||
ALLOW_NOTIFY_IP_SOURCE_RANGE, | ||
ALLOW_PAGOPA_IP_SOURCE_RANGE, | ||
ALLOW_SESSION_HANDLER_IP_SOURCE_RANGE, | ||
API_BASE_PATH, | ||
AUTHENTICATION_BASE_PATH, | ||
BONUS_API_BASE_PATH, | ||
BPD_BASE_PATH, | ||
DEFAULT_APPINSIGHTS_SAMPLING_PERCENTAGE, | ||
ENV, | ||
MYPORTAL_BASE_PATH, | ||
PAGOPA_BASE_PATH | ||
} from "../src/config"; | ||
import { initAppInsights } from "../src/utils/appinsights"; | ||
import { | ||
getCurrentBackendVersion, | ||
getValueFromPackageJson | ||
} from "../src/utils/package"; | ||
|
||
const authenticationBasePath = AUTHENTICATION_BASE_PATH; | ||
const APIBasePath = API_BASE_PATH; | ||
const BonusAPIBasePath = BONUS_API_BASE_PATH; | ||
const PagoPABasePath = PAGOPA_BASE_PATH; | ||
const MyPortalBasePath = MYPORTAL_BASE_PATH; | ||
const BPDBasePath = BPD_BASE_PATH; | ||
|
||
/** | ||
* If APPINSIGHTS_INSTRUMENTATIONKEY env is provided initialize an App Insights Client | ||
* WARNING: When the key is provided several information are collected automatically | ||
* and sent to App Insights. | ||
* To see what kind of informations are automatically collected | ||
* @see: utils/appinsights.js into the class AppInsightsClientBuilder | ||
*/ | ||
const maybeAppInsightsClient = fromNullable( | ||
process.env.APPINSIGHTS_INSTRUMENTATIONKEY | ||
).map(k => | ||
initAppInsights(k, { | ||
applicationVersion: getCurrentBackendVersion(), | ||
cloudRole: getValueFromPackageJson("name"), | ||
disableAppInsights: process.env.APPINSIGHTS_DISABLED === "true", | ||
samplingPercentage: process.env.APPINSIGHTS_SAMPLING_PERCENTAGE | ||
? parseInt(process.env.APPINSIGHTS_SAMPLING_PERCENTAGE, 10) | ||
: DEFAULT_APPINSIGHTS_SAMPLING_PERCENTAGE | ||
}) | ||
); | ||
|
||
// tslint:disable-next-line: no-let | ||
let logger: Context["log"] | undefined; | ||
const contextTransport = new AzureContextTransport(() => logger, { | ||
level: "debug" | ||
}); | ||
winston.add(contextTransport); | ||
|
||
// Setup Express | ||
const init = newApp({ | ||
APIBasePath, | ||
BPDBasePath, | ||
BonusAPIBasePath, | ||
MyPortalBasePath, | ||
PagoPABasePath, | ||
allowBPDIPSourceRange: ALLOW_BPD_IP_SOURCE_RANGE, | ||
allowMyPortalIPSourceRange: ALLOW_MYPORTAL_IP_SOURCE_RANGE, | ||
allowNotifyIPSourceRange: ALLOW_NOTIFY_IP_SOURCE_RANGE, | ||
allowPagoPAIPSourceRange: ALLOW_PAGOPA_IP_SOURCE_RANGE, | ||
allowSessionHandleIPSourceRange: ALLOW_SESSION_HANDLER_IP_SOURCE_RANGE, | ||
appInsightsClient: maybeAppInsightsClient.toUndefined(), | ||
authenticationBasePath, | ||
env: ENV | ||
}).then(app => { | ||
secureExpressApp(app); | ||
return { | ||
app, | ||
azureFunctionHandler: createAzureFunctionHandler(app) | ||
}; | ||
}); | ||
|
||
// Binds the express app to an Azure Function handler | ||
function httpStart(context: Context): void { | ||
logger = context.log; | ||
init | ||
.then(({ app, azureFunctionHandler }) => { | ||
setAppContext(app, context); | ||
azureFunctionHandler(context); | ||
}) | ||
.catch(context.log); | ||
} | ||
|
||
export default httpStart; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<TargetFramework>netcoreapp3.1</TargetFramework> | ||
<AzureFunctionsVersion>v3</AzureFunctionsVersion> | ||
<WarningsAsErrors></WarningsAsErrors> | ||
<DefaultItemExcludes>**</DefaultItemExcludes> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.2.2" /> | ||
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="4.0.1" /> | ||
<PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.1.8" /> | ||
</ItemGroup> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"version": "2.0", | ||
"logging": { | ||
"logLevel": { | ||
"default": "Information" | ||
} | ||
}, | ||
"extensions": { | ||
"http": { | ||
"routePrefix": "" | ||
}, | ||
"durableTask": { | ||
"hubName": "%SLOT_TASK_HUBNAME%" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ import { | |
appConfig, | ||
BONUS_API_CLIENT, | ||
CACHE_MAX_AGE_SECONDS, | ||
DISABLE_BODY_PARSER, | ||
ENV, | ||
FF_BONUS_ENABLED, | ||
getClientProfileRedirectionUrl, | ||
|
@@ -54,6 +55,7 @@ import ServicesController from "./controllers/servicesController"; | |
import SessionController from "./controllers/sessionController"; | ||
import UserMetadataController from "./controllers/userMetadataController"; | ||
|
||
import * as mime from "mime"; | ||
import { log } from "./utils/logger"; | ||
import checkIP from "./utils/middleware/checkIP"; | ||
|
||
|
@@ -64,6 +66,7 @@ import * as appInsights from "applicationinsights"; | |
import { tryCatch2v } from "fp-ts/lib/Either"; | ||
import { isEmpty, StrMap } from "fp-ts/lib/StrMap"; | ||
import { fromLeft, taskEither, tryCatch } from "fp-ts/lib/TaskEither"; | ||
import * as fs from "fs"; | ||
import { VersionPerPlatform } from "../generated/public/VersionPerPlatform"; | ||
import BonusController from "./controllers/bonusController"; | ||
import SessionLockController from "./controllers/sessionLockController"; | ||
|
@@ -131,7 +134,7 @@ export interface IAppFactoryParameters { | |
BPDBasePath: string; | ||
} | ||
|
||
// tslint:disable-next-line: no-big-function | ||
// tslint:disable-next-line: cognitive-complexity no-big-function | ||
export function newApp({ | ||
env, | ||
allowNotifyIPSourceRange, | ||
|
@@ -250,18 +253,45 @@ export function newApp({ | |
// | ||
// Setup parsers | ||
// | ||
if (!DISABLE_BODY_PARSER) { | ||
// Parse the incoming request body. This is needed by Passport spid strategy. | ||
app.use(bodyParser.json()); | ||
|
||
// Parse the incoming request body. This is needed by Passport spid strategy. | ||
app.use(bodyParser.json()); | ||
|
||
// Parse an urlencoded body. | ||
app.use(bodyParser.urlencoded({ extended: true })); | ||
// Parse an urlencoded body. | ||
app.use(bodyParser.urlencoded({ extended: true })); | ||
} | ||
|
||
// | ||
// Define the folder that contains the public assets. | ||
// | ||
|
||
app.use(express.static("public")); | ||
app.get(/(\.html|\.svg|\.png)$/, async (req, res, next) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess the result of this call can be cached using appcache, what about this? |
||
try { | ||
const path = "public" + req.path; | ||
if (!fs.existsSync(path)) { | ||
return next(); | ||
} | ||
const stat = await fs.promises.stat(path); | ||
if (stat.isDirectory()) { | ||
return next(); | ||
} | ||
const type = mime.lookup(path); | ||
if (type) { | ||
const charset = mime.charsets.lookup(type); | ||
res.setHeader( | ||
"Content-Type", | ||
// tslint:disable-next-line: restrict-plus-operands | ||
type + (charset ? `; charset=${charset}` : "") | ||
); | ||
} | ||
const content = await fs.promises.readFile(path); | ||
res.setHeader("Content-Length", stat.size); | ||
res.status(200).send(content); | ||
} catch (err) { | ||
log.error(`static|Error retrieving static file asset|error:%s`, err); | ||
return next(err); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not clear to me why we introduced this behaviour. Besides that, we can put this in a middleware function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic is required because the express default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can just move it in a function declared inside the same module There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 94282ce |
||
}); | ||
|
||
// | ||
// Initializes Passport for incoming requests. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,8 +133,6 @@ describe("SessionLockController#lockUserSession", () => { | |
}); | ||
}); | ||
|
||
|
||
|
||
describe("SessionLockController#unlockUserSession", () => { | ||
it("should fail on invalid fiscal code", async () => { | ||
const req = mockReq({ params: { fiscal_code: "invalid" } }); | ||
|
@@ -175,7 +173,7 @@ describe("SessionLockController#unlockUserSession", () => { | |
mockRedisUserMetadataStorage | ||
); | ||
|
||
const response = await controller.lockUserSession(req); | ||
const response = await controller.unlockUserSession(req); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😅 |
||
response.apply(res); | ||
|
||
expect(res.status).toHaveBeenCalledWith(200); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does SPID login work without this?