Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
53 changes: 53 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"root": true,
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended"
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
"no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
"no-console": "off",
"eqeqeq": ["error", "always"],
"curly": ["error", "all"],
"no-eval": "error",
"no-implied-eval": "error",
"no-new-func": "error",
"no-script-url": "error",
"prefer-const": "warn",
"no-var": "error",
"no-throw-literal": "error",
"no-return-await": "warn",
"require-await": "warn"
},
"overrides": [
{
"files": ["**/*.ts", "**/*.tsx"],
"parser": "@typescript-eslint/parser",
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-non-null-assertion": "warn"
}
}
],
"ignorePatterns": [
"node_modules/",
"dist/",
"build/",
"*.min.js"
]
}
11 changes: 11 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf"
}
27 changes: 22 additions & 5 deletions 05-advanced-prompts/javascript/solution.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,30 @@ app.get('/', [
});

// Use HTTPS instead of HTTP
const options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert')
};
// SECURITY: Use absolute paths and proper error handling for certificates
const path = await import('path');
const certDir = process.env.CERT_DIR || process.cwd();

// SECURITY: Validate certificate directory is within allowed path
const resolvedCertDir = path.resolve(certDir);
if (!resolvedCertDir.startsWith(process.cwd())) {
throw new Error('Certificate directory must be within the application directory');
}

let options;
try {
options = {
key: fs.readFileSync(path.join(resolvedCertDir, 'server.key')),
cert: fs.readFileSync(path.join(resolvedCertDir, 'server.cert'))
};
} catch (error) {
console.error('Failed to load SSL certificates:', error.message);
console.error('Please ensure server.key and server.cert files exist in the certificate directory');
process.exit(1);
}

https.createServer(options, app).listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
console.log(`Server is running securely on port ${PORT}`);
});

/*
Expand Down
35 changes: 29 additions & 6 deletions 05-advanced-prompts/python/aoai-solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,50 @@

# - Implement error handling to provide meaningful error messages to the user in case of errors. You can use the @app.errorhandler() decorator to handle exceptions and return an error response.

from flask import Flask, request
import os
from flask import Flask, render_template_string
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, Length, Email
from markupsafe import escape

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret_key'
# SECURITY: Load secret key from environment variable instead of hardcoding
app.config['SECRET_KEY'] = os.environ.get('FLASK_SECRET_KEY', os.urandom(32))

class HelloForm(FlaskForm):
name = StringField('Name', validators=[DataRequired(), Length(min=3)])
email = StringField('Email', validators=[DataRequired(), Email()])
submit = SubmitField('Submit')

# Form template with proper CSRF protection and escaping
FORM_TEMPLATE = '''
<!DOCTYPE html>
<html>
<head><title>Hello Form</title></head>
<body>
<form method="POST">
{{ form.hidden_tag() }}
<p>{{ form.name.label }} {{ form.name(size=32) }}
{% for error in form.name.errors %}<span style="color: red;">[{{ error }}]</span>{% endfor %}</p>
<p>{{ form.email.label }} {{ form.email(size=32) }}
{% for error in form.email.errors %}<span style="color: red;">[{{ error }}]</span>{% endfor %}</p>
<p>{{ form.submit() }}</p>
</form>
</body>
</html>
'''

@app.route('/', methods=['GET', 'POST'])
def hello():
form = HelloForm()
if form.validate_on_submit():
name = form.name.data
email = form.email.data
return f'Hello, {name} ({email})!'
return form.render_template()
# SECURITY: Use escape() to prevent XSS attacks
safe_name = escape(form.name.data)
safe_email = escape(form.email.data)
return f'Hello, {safe_name} ({safe_email})!'
# SECURITY: Use Flask's render_template_string for proper escaping
return render_template_string(FORM_TEMPLATE, form=form)

@app.errorhandler(400)
def bad_request(error):
Expand Down
5 changes: 5 additions & 0 deletions 06-text-generation-apps/js-githubmodels/app.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import ModelClient from "@azure-rest/ai-inference";
import { AzureKeyCredential } from "@azure/core-auth";

// SECURITY: Validate required environment variable
const token = process.env["GITHUB_TOKEN"];
if (!token) {
throw new Error("GITHUB_TOKEN environment variable is required. Please set it before running this application.");
}

const endpoint = "https://models.inference.ai.azure.com";
const modelName = "gpt-4o";

Expand Down
62 changes: 51 additions & 11 deletions 06-text-generation-apps/python/aoai-app-recipe.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,67 @@
from openai import AzureOpenAI
import os
import re
from dotenv import load_dotenv

# load environment variables from .env file
load_dotenv()

# configure Azure OpenAI service client
# SECURITY: Validate environment variables with helpful error messages
def get_required_env(var_name: str) -> str:
"""Get a required environment variable or raise an error with helpful message."""
value = os.getenv(var_name)
if not value:
raise ValueError(f"Missing required environment variable: {var_name}. Please set it in your .env file.")
return value

# SECURITY: Input validation functions
def validate_number_input(value: str, min_val: int = 1, max_val: int = 20) -> int:
"""Validate and sanitize numeric input."""
try:
num = int(value)
if num < min_val or num > max_val:
raise ValueError(f"Number must be between {min_val} and {max_val}")
return num
except ValueError:
raise ValueError(f"Please enter a valid number between {min_val} and {max_val}")

def validate_text_input(value: str, max_length: int = 500) -> str:
"""Validate and sanitize text input to prevent prompt injection."""
if len(value) > max_length:
raise ValueError(f"Input too long. Maximum {max_length} characters allowed.")
# Remove potentially dangerous characters/patterns
sanitized = re.sub(r'[<>{}[\]|\\`]', '', value)
# Limit to alphanumeric, spaces, commas, and basic punctuation
if not re.match(r'^[\w\s,.\'-]+$', sanitized, re.UNICODE):
raise ValueError("Input contains invalid characters")
return sanitized.strip()

# configure Azure OpenAI service client
client = AzureOpenAI(
azure_endpoint = os.environ["AZURE_OPENAI_ENDPOINT"],
api_key=os.environ['AZURE_OPENAI_API_KEY'],
api_version = "2023-10-01-preview"
)
azure_endpoint=get_required_env("AZURE_OPENAI_ENDPOINT"),
api_key=get_required_env('AZURE_OPENAI_API_KEY'),
api_version="2023-10-01-preview"
)

deployment=os.environ['AZURE_OPENAI_DEPLOYMENT']
deployment = get_required_env('AZURE_OPENAI_DEPLOYMENT')

no_recipes = input("No of recipes (for example, 5: ")
# SECURITY: Validate all user inputs
try:
no_recipes_input = input("No of recipes (for example, 5): ")
no_recipes = validate_number_input(no_recipes_input, 1, 20)

ingredients = input("List of ingredients (for example, chicken, potatoes, and carrots: ")
ingredients_input = input("List of ingredients (for example, chicken, potatoes, and carrots): ")
ingredients = validate_text_input(ingredients_input, 500)

filter = input("Filter (for example, vegetarian, vegan, or gluten-free: ")
filter_input = input("Filter (for example, vegetarian, vegan, or gluten-free): ")
filter_value = validate_text_input(filter_input, 100) if filter_input.strip() else "none"
except ValueError as e:
print(f"Input validation error: {e}")
exit(1)

# interpolate the number of recipes into the prompt an ingredients
prompt = f"Show me {no_recipes} recipes for a dish with the following ingredients: {ingredients}. Per recipe, list all the ingredients used, no {filter}: "
# interpolate the number of recipes into the prompt and ingredients
# Note: Using validated and sanitized inputs
prompt = f"Show me {no_recipes} recipes for a dish with the following ingredients: {ingredients}. Per recipe, list all the ingredients used, no {filter_value}: "
messages = [{"role": "user", "content": prompt}]

completion = client.chat.completions.create(model=deployment, messages=messages, max_tokens=600, temperature = 0.1)
Expand Down
5 changes: 5 additions & 0 deletions 07-building-chat-applications/js-githubmodels/app.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import ModelClient from "@azure-rest/ai-inference";
import { AzureKeyCredential } from "@azure/core-auth";

// SECURITY: Validate required environment variable
const token = process.env["GITHUB_TOKEN"];
if (!token) {
throw new Error("GITHUB_TOKEN environment variable is required. Please set it before running this application.");
}

const endpoint = "https://models.inference.ai.azure.com";

/* By using the Azure AI Inference SDK, you can easily experiment with different models
Expand Down
6 changes: 5 additions & 1 deletion 08-building-search-applications/js-githubmodels/app.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import ModelClient from "@azure-rest/ai-inference";
import { isUnexpected } from "@azure-rest/ai-inference";
import { AzureKeyCredential } from "@azure/core-auth";
import { brotliDecompress } from "zlib";

// SECURITY: Validate required environment variable
const token = process.env["GITHUB_TOKEN"];
if (!token) {
throw new Error("GITHUB_TOKEN environment variable is required. Please set it before running this application.");
}

const endpoint = "https://models.inference.ai.azure.com";

/* By using the Azure AI Inference SDK, you can easily experiment with different models
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ def gen_metadata(playlist_item):
metadata["videoId"] = playlist_item["snippet"]["resourceId"]["videoId"]
metadata["description"] = playlist_item["snippet"]["description"]

# save the metadata as a .json file
json.dump(metadata, open(filename, "w", encoding="utf-8"))
# SECURITY: Use context manager to properly close file handles
with open(filename, "w", encoding="utf-8") as out_file:
json.dump(metadata, out_file)


def get_transcript(playlist_item, counter_id):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,9 @@ def process_queue(progress, task):
print(f"From function call: {filename}\t{speakers}")

metadata["speaker"] = speakers
json.dump(metadata, open(filename, "w", encoding="utf-8"))
# SECURITY: Use context manager to properly close file handles
with open(filename, "w", encoding="utf-8") as out_file:
json.dump(metadata, out_file)

q.task_done()
time.sleep(0.2)
Expand Down
37 changes: 26 additions & 11 deletions 09-building-image-applications/python/oai-app.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
from openai import OpenAI
from openai import OpenAI, OpenAIError
import os
import requests
from requests.exceptions import RequestException
from PIL import Image
import dotenv
from dotenv import load_dotenv

# import dotenv
dotenv.load_dotenv()

client = OpenAI()
# Load environment variables from .env file
load_dotenv()

# SECURITY: Validate API key is present
api_key = os.getenv('OPENAI_API_KEY')
if not api_key:
raise ValueError("OPENAI_API_KEY environment variable is required. Please set it in your .env file.")

client = OpenAI(api_key=api_key)


try:
Expand All @@ -31,18 +37,27 @@
# Retrieve the generated image
print(generation_response)

image_url = generation_response.data[0].url # extract image URL from response
generated_image = requests.get(image_url).content # download the image
image_url = generation_response.data[0].url # extract image URL from response

# SECURITY: Add timeout and error handling for HTTP request
try:
response = requests.get(image_url, timeout=30)
response.raise_for_status() # Raise exception for HTTP errors
generated_image = response.content
except RequestException as req_err:
print(f"Failed to download generated image: {req_err}")
raise

with open(image_path, "wb") as image_file:
image_file.write(generated_image)

# Display the image in the default image viewer
image = Image.open(image_path)
image.show()

# catch exceptions
except openai.InvalidRequestError as err:
print(err)
# SECURITY: Catch specific OpenAI exceptions
except OpenAIError as err:
print(f"OpenAI API error: {err}")

# ---creating variation below---

Expand Down
Loading