Skip to content

Commit

Permalink
Bar codes for credential offers on our openid4vci server page. (#780)
Browse files Browse the repository at this point in the history
Signed-off-by: Peter Sorotokin <[email protected]>
  • Loading branch information
sorotokin authored Nov 18, 2024
1 parent 1e46506 commit 9d2d1dd
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 9 deletions.
1 change: 1 addition & 0 deletions server-openid4vci/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies {
implementation(libs.kotlinx.io.bytestring)
implementation(libs.bouncy.castle.bcprov)
implementation(libs.nimbus.oauth2.oidc.sdk)
implementation(libs.zxing.core)

testImplementation(libs.junit)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.android.identity.server.openid4vci

import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import com.google.zxing.qrcode.encoder.Encoder
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import java.awt.image.BufferedImage
import java.awt.image.DataBufferByte
import javax.imageio.ImageIO

/**
* Servlet that encodes text string (passed as `q` parameter) into a QR code.
*/
class QrServlet : BaseServlet() {
override fun doGet(req: HttpServletRequest, resp: HttpServletResponse) {
val str = req.getParameter("q") ?: throw IllegalStateException("q parameter required")
val qr = Encoder.encode(str, ErrorCorrectionLevel.L, null)
val matrix = qr.matrix
val width = matrix.width
val height = matrix.height
val image = BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY)
val pixels = (image.raster.dataBuffer as DataBufferByte).data
var index = 0
for (y in 0 until height) {
for (x in 0 until width) {
pixels[index++] = if (matrix[x, y].toInt() == 0) -1 else 0
}
}
resp.contentType = "image/png"
ImageIO.write(image, "png", resp.outputStream)
}
}
12 changes: 12 additions & 0 deletions server/src/main/webapp/WEB-INF/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,18 @@
<url-pattern>/openid4vci/credential_request</url-pattern>
</servlet-mapping>

<servlet>
<display-name>QrServlet</display-name>
<servlet-name>QrServlet</servlet-name>
<servlet-class>com.android.identity.server.openid4vci.QrServlet</servlet-class>
<load-on-startup>10</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>QrServlet</servlet-name>
<url-pattern>/openid4vci/qr</url-pattern>
</servlet-mapping>

<servlet>
<display-name>WellKnownOpenidCredentialIssuanceServlet</display-name>
<servlet-name>WellKnownOpenidCredentialIssuanceServlet</servlet-name>
Expand Down
22 changes: 13 additions & 9 deletions server/src/main/webapp/openid4vci/display_metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@ async function displayMetadata() {
let issuance = await (await fetch(".well-known/openid-credential-issuer")).json();
let hi = document.createElement("img");
hi.setAttribute("src", issuance.display[0].logo?.uri);
hi.setAttribute("style", "width:20%; float: right");
hi.setAttribute("style", "width:20%;max-width:180px;float: right");
body.appendChild(hi);
let h1 = document.createElement("h1");
h1.textContent = issuance.display[0].name;
body.appendChild(h1);
let list = document.createElement("ul");
let configs = issuance.credential_configurations_supported;
let h2 = document.createElement("h2");
h2.textContent = "Credentials available from this server";
body.appendChild(h2);
for (let configId in configs) {
let config = configs[configId];
let item = document.createElement("li");
list.appendChild(item);
let item = document.createElement("div");
item.setAttribute("style", "border-top: 2px solid black; margin: 1em")
body.appendChild(item);
let h3 = document.createElement("h3");
item.appendChild(h3);
let a = document.createElement("a");
item.appendChild(a);
let h3 = document.createElement("h3");
a.appendChild(h3);
h3.textContent = config.display[0].name;
let img = document.createElement("img");
img.setAttribute("src", config.display[0].logo?.uri);
img.setAttribute("style", "width:80%;margin-bottom:2em");
img.setAttribute("style", "width:80%;margin:1em;max-width:500px");
a.appendChild(img);
let url = location.href.substring(0, location.href.lastIndexOf("/"));
let offer = {
Expand All @@ -36,7 +36,11 @@ async function displayMetadata() {
authorization_code:{}
}
};
a.href = "openid-credential-offer://?credential_offer=" + encodeURIComponent(JSON.stringify(offer))
let href = "openid-credential-offer://?credential_offer=" + encodeURIComponent(JSON.stringify(offer));
a.href = href;
let qr = document.createElement("img");
qr.setAttribute("src", "qr?q=" + encodeURIComponent(href));
qr.setAttribute("style", "width:70%;margin:1em;margin-left:2em;image-rendering: pixelated;max-width:450px");
item.appendChild(qr);
}
body.appendChild(list)
}

0 comments on commit 9d2d1dd

Please sign in to comment.