refactor: minor changes

- jams-react-client: fix request spam on devices tab
- don't send hashed password in response when creating a user

Change-Id: I3c576003d57ef84ff523ebbf14ac611793a8b750
This commit is contained in:
Léo Banno-Cloutier
2023-08-15 11:21:53 -04:00
parent 00922a448e
commit daae2398c8
21 changed files with 226 additions and 260 deletions

View File

@ -1,5 +1,7 @@
.git
.gitignore
.gitmodules
.gitreview
Dockerfile
.dockerignore
@ -7,4 +9,13 @@ Dockerfile
**/node_modules
**/target
.gradle
.idea
.vscode
README.md
derby.log
extras
jams
jams-server/src/main/resources/webapp

View File

@ -22,9 +22,9 @@ COPY jams-server/pom.xml jams-server/pom.xml
# RUN mvn dependency:resolve --fail-never
# RUN mvn dependency:go-offline --fail-never -am
RUN mvn install -pl ad-connector,authentication-module,datastore,jami-dht,jami-nameserver,jams-ca,jams-common,jams-launcher,ldap-connector,jams-server -am -DskipTests
COPY . .
FROM build as dev
COPY . .
WORKDIR /app
RUN mkdir -p /app/jams-server/src/main/resources/webapp \
&& echo '<h1>Dev build, this is a placeholder index.html. Please connect to <a href="http://localhost:3000">localhost:3000</a> instead</h1>' \
@ -38,18 +38,16 @@ CMD java -jar jams-server.jar 8080 \
FROM build as prod
WORKDIR /app/jams-react-client
COPY jams-react-client .
RUN npm run build
RUN mkdir -p ../jams-server/src/main/resources/webapp \
&& mv build/* ../jams-server/src/main/resources/webapp
WORKDIR /app
COPY . .
RUN mkdir -p jams-server/src/main/resources/webapp \
&& mv jams-react-client/build/* jams-server/src/main/resources/webapp
RUN mvn package
ENV JAMS_VERSION=3.5
RUN python3 generate-versions.py net.jami.jams.ca.JamsCA $JAMS_VERSION libs/cryptoengine.jar
RUN python3 generate-versions.py net.jami.jams.authmodule.UserAuthenticationModule $JAMS_VERSION libs/authentication-module.jar
RUN python3 generate-versions.py net.jami.jams.server.Server $JAMS_VERSION jams-server.jar
RUN python3 generate-versions.py net.jami.jams.ad.connector.ADConnector $JAMS_VERSION libs/ad-connector.jar
RUN python3 generate-versions.py net.jami.jams.ldap.connector.LDAPConnector $JAMS_VERSION libs/ldap-connector.jar
RUN python3 generate-versions.py $JAMS_VERSION
RUN ./build-doc.sh
WORKDIR /app/jams

View File

@ -4,6 +4,9 @@ import sys
from pathlib import Path
here = Path(__file__).parent
def read_versions(versions_file: Path) -> dict:
if not versions_file.exists():
return {}
@ -12,31 +15,57 @@ def read_versions(versions_file: Path) -> dict:
return json.load(f)
def main() -> None:
here = Path(__file__).parent
versions_file = here / "versions.json"
class_name = sys.argv[1]
version = sys.argv[2]
filename = sys.argv[3]
versions = read_versions(versions_file)
def get_md5_hash(filename: str) -> str:
md5_hash = hashlib.md5()
with open(here / "jams" / filename, "rb") as jar:
md5_hash.update(jar.read())
return md5_hash.hexdigest()
def generate_versions(class_name: str, version: str, filename: str) -> None:
versions_file = here / "versions.json"
versions = read_versions(versions_file)
versions[class_name] = {
"version": version,
"filename": filename,
"md5": md5_hash.hexdigest(),
"md5": get_md5_hash(filename),
}
with open(versions_file, "w") as f:
json.dump(versions, f, indent=4)
def main() -> None:
if len(sys.argv) == 2:
version = sys.argv[1]
class_to_filename = {
"net.jami.jams.ca.JamsCA": "libs/cryptoengine.jar",
"net.jami.jams.authmodule.UserAuthenticationModule": "libs/authentication-module.jar",
"net.jami.jams.server.Server": "jams-server.jar",
"net.jami.jams.ad.connector.ADConnector": "libs/ad-connector.jar",
"net.jami.jams.ldap.connector.LDAPConnector": "libs/ldap-connector.jar",
}
for class_name, filename in class_to_filename.items():
generate_versions(class_name, version, filename)
return
if len(sys.argv) != 4:
print(f"Usage: {sys.argv[0]} (<version> | <class_name> <version> <filename>)")
sys.exit(1)
class_name = sys.argv[1]
version = sys.argv[2]
filename = sys.argv[3]
generate_versions(class_name, version, filename)
if __name__ == "__main__":
main()

View File

@ -44,6 +44,8 @@ import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Date;
@Slf4j
@ -51,7 +53,6 @@ public class UserBuilder {
public static User generateUser(User user) {
try {
long now = System.currentTimeMillis();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(4096);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
@ -60,23 +61,14 @@ public class UserBuilder {
MessageDigest.getInstance(MessageDigestAlgorithms.SHA_1)
.digest(keyPair.getPublic().getEncoded());
user.getX509Fields().setUid(Hex.encodeHexString(digest));
X509v3CertificateBuilder builder =
new X509v3CertificateBuilder(
new JcaX509CertificateHolder(JamsCA.CA.getCertificate()).getSubject(),
new BigInteger(128, new SecureRandom()),
new Date(now - SHIFT),
new Date(now + JamsCA.userLifetime),
new X500Name(user.getX509Fields().getDN()),
SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()));
user.setPrivateKey(keyPair.getPrivate());
user.setCertificate(
CertificateSigner.signCertificate(
JamsCA.CA.getPrivateKey(), builder, ExtensionLibrary.userExtensions));
log.info(
"New user certificate: Not valid after: "
+ user.getCertificate().getNotAfter());
String dn = user.getX509Fields().getDN();
SubjectPublicKeyInfo publicKeyInfo =
SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
X509Certificate certificate =
generateSignedCertificate(dn, JamsCA.userLifetime, publicKeyInfo);
user.setCertificate(certificate);
return user;
} catch (Exception e) {
log.error("Could not generate a user certificate: " + e);
@ -89,28 +81,18 @@ public class UserBuilder {
}
public static User refreshUser(User user, long userLifeTime) {
long now = System.currentTimeMillis();
X509Fields x509 = new X509Fields();
x509.setCommonName(user.getUsername());
x509.setUid(user.getJamiId());
user.setX509Fields(x509);
try {
X509v3CertificateBuilder builder =
new X509v3CertificateBuilder(
new JcaX509CertificateHolder(JamsCA.CA.getCertificate()).getSubject(),
new BigInteger(128, new SecureRandom()),
new Date(now - SHIFT),
new Date(now + userLifeTime),
new X500Name(user.getX509Fields().getDN()),
new JcaX509CertificateHolder(user.getCertificate())
.getSubjectPublicKeyInfo());
user.setCertificate(
CertificateSigner.signCertificate(
JamsCA.CA.getPrivateKey(), builder, ExtensionLibrary.userExtensions));
log.info(
"Refreshed user certificate: Not valid after: "
+ user.getCertificate().getNotAfter());
String dn = user.getX509Fields().getDN();
SubjectPublicKeyInfo publicKeyInfo =
new JcaX509CertificateHolder(user.getCertificate()).getSubjectPublicKeyInfo();
X509Certificate certificate =
generateSignedCertificate(dn, userLifeTime, publicKeyInfo);
user.setCertificate(certificate);
return user;
} catch (Exception e) {
@ -118,4 +100,24 @@ public class UserBuilder {
return null;
}
}
private static X509Certificate generateSignedCertificate(
String dn, long userLifeTime, SubjectPublicKeyInfo publicKeyInfo)
throws CertificateEncodingException {
long now = System.currentTimeMillis();
X509v3CertificateBuilder builder =
new X509v3CertificateBuilder(
new JcaX509CertificateHolder(JamsCA.CA.getCertificate()).getSubject(),
new BigInteger(128, new SecureRandom()),
new Date(now - SHIFT),
new Date(now + userLifeTime),
new X500Name(dn),
publicKeyInfo);
X509Certificate certificate =
CertificateSigner.signCertificate(
JamsCA.CA.getPrivateKey(), builder, ExtensionLibrary.userExtensions);
log.info("User certificate: Not valid after: {}", certificate.getNotAfter());
return certificate;
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Authors: William Enright <william.enright@savoirfairelinux.com>
* Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com>
* Johnny Flores <johnny.flores@savoirfairelinux.com>
* Mohammed Raza <mohammed.raza@savoirfairelinux.com>
* Felix Sidokhine <felix.sidokhine@savoirfairelinux.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.jami.jams.common.objects.requests;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class DeviceRevocationRequest {
private String owner;
private String deviceId;
public DeviceRevocationRequest(String username, String deviceId) {
this.owner = owner;
this.deviceId = deviceId;
}
}

View File

@ -25,7 +25,6 @@ public class ContactAdapter implements JsonSerializer<Contact>, JsonDeserializer
contact.setUri(input.get("uri").getAsString());
contact.setConversationId(input.get("conversationId").getAsString());
long timeAdded = 0L;
if (input.has("added")) {
timeAdded = input.get("added").getAsLong();

View File

@ -66,6 +66,8 @@ public class X509Utils {
private static final String PPK_TAIL = "\n-----END PUBLIC KEY-----";
public static PrivateKey getKeyFromPEMString(String keyString) {
if (keyString.isEmpty()) return null;
try {
PEMParser parser = new PEMParser(new StringReader(keyString));
Object parsedObject = parser.readObject();

View File

@ -40,7 +40,7 @@ import i18next from "i18next";
const useStyles = makeStyles(styles);
export default function Devices(props) {
export default function Devices({ username }) {
const classes = useStyles();
const history = useHistory();
@ -49,9 +49,7 @@ export default function Devices(props) {
const [displayName, setDisplayName] = useState("");
const [openEdit, setOpenEdit] = useState(false);
const [openRevoke, setOpenRevoke] = useState(false);
const userData = {
username: props.username,
};
const userData = { username };
useEffect(() => {
auth.checkDirectoryType(() => {
@ -94,7 +92,7 @@ export default function Devices(props) {
});
}
});
}, [history, selectedDevice, userData]);
}, []);
function getDeviceStatus(device) {
if (!device.revoked) {
@ -134,7 +132,7 @@ export default function Devices(props) {
const handleUpdate = () => {
if (auth.hasAdminScope()) {
const data = {
username: props.username,
username,
deviceId: selectedDevice.deviceId,
deviceName: displayName,
};
@ -188,7 +186,7 @@ export default function Devices(props) {
const handleDeviceRevoke = () => {
if (auth.hasAdminScope()) {
const data = {
username: props.username,
username,
deviceId: selectedDevice.deviceId,
};
axios(

View File

@ -1,9 +1,7 @@
import React from "react";
// nodejs library to set properties for components
import PropTypes from "prop-types";
// @mui/material components
import React, { FC } from "react";
import { makeStyles } from "@mui/styles";
import Grid from "@mui/material/Grid";
import { Grid, GridTypeMap } from "@mui/material";
import { OverridableComponent } from "@mui/material/OverridableComponent";
const styles = {
grid: {
@ -13,16 +11,17 @@ const styles = {
const useStyles = makeStyles(styles);
export default function GridItem(props) {
interface GridItemProps extends OverridableComponent<GridTypeMap> {
children: React.ReactNode;
}
const GridItem: FC<GridItemProps> = ({ children, ...rest }) => {
const classes = useStyles();
const { children, ...rest } = props;
return (
<Grid item {...rest} className={classes.grid}>
{children}
</Grid>
);
}
GridItem.propTypes = {
children: PropTypes.node,
};
export default GridItem;

View File

@ -2,7 +2,7 @@ const uri = "";
const current_uri = window.location.href;
const backend_address = new URL(
process.env.NODE_ENV === "development"
? "http://localhost:8080"
? window.location.origin.replace(/\d+$/, "") + "8080"
: window.location.href
);
const url_path = backend_address.protocol + "//" + backend_address.hostname;

View File

@ -39,7 +39,7 @@ export const PolicyDataContextProvider: FC<Props> = ({
children,
}) => {
const [policyData, setPolicyData] = useState(DEFAULT_POLICY_DATA);
const [snackbar, setSnackbar] = useState({
const [snackbar, setSnackbar] = useState<SnackbarProps>({
open: false,
severity: "success",
message: "",

View File

@ -19,9 +19,7 @@ export const DEFAULT_UI_CUSTOMIZATION = {
logoSize: 100,
};
export type UiCustomization = typeof DEFAULT_UI_CUSTOMIZATION;
export const DEFAULT_POLICY_DATA = {
const DEFAULT_POLICY_DATA_PERMISSIONS = {
videoEnabled: true,
publicInCalls: false,
autoAnswer: false,
@ -30,7 +28,9 @@ export const DEFAULT_POLICY_DATA = {
rendezVous: false,
blueprintModerators: [],
};
const DEFAULT_POLICY_DATA_CONFIGURATION = {
upnpEnabled: true,
selectedTurnOption: "defaultTurn",
@ -41,8 +41,17 @@ export const DEFAULT_POLICY_DATA = {
selectedDHTProxyOption: "defaultDHTProxy",
proxyServer: "dhtproxy.jami.net",
dhtProxyListUrl: "",
};
export const DEFAULT_POLICY_DATA = {
...DEFAULT_POLICY_DATA_PERMISSIONS,
...DEFAULT_POLICY_DATA_CONFIGURATION,
uiCustomization: DEFAULT_UI_CUSTOMIZATION,
};
export type PolicyData = typeof DEFAULT_POLICY_DATA;
export type UiCustomization = typeof DEFAULT_UI_CUSTOMIZATION;
export type PolicyDataPermissions = typeof DEFAULT_POLICY_DATA_PERMISSIONS;
export type PolicyDataNetwork = typeof DEFAULT_POLICY_DATA_CONFIGURATION;
export interface PolicyData extends PolicyDataPermissions, PolicyDataNetwork {
uiCustomization: UiCustomization;
}

View File

@ -186,8 +186,8 @@ export const _updatePolicyData = (
policyData: PolicyData,
setPolicyData: Dispatch<SetStateAction<PolicyData>>,
field: string,
value: string,
setSnackbar: (snackbar: any) => void
value: any,
setSnackbar: (snackbar: SnackbarProps) => void
) => {
setPolicyData((state) => ({ ...state, [field]: value }));

View File

@ -413,7 +413,6 @@ export default function Users(props) {
xs={12}
sm={12}
md={2}
wrap="nowrap"
key={contact.uri}
style={{ display: contact.display }}
>

View File

@ -102,9 +102,8 @@ public class RegisterDeviceFlow {
});
return response;
} catch (Exception e) {
log.error(
"An exception has occurred while trying to enroll a device with error {}",
e.getMessage());
log.error("An exception has occurred while trying to enroll a device");
e.printStackTrace();
return null;
}
}

View File

@ -38,15 +38,9 @@ import net.jami.jams.common.objects.contacts.Contact;
import net.jami.jams.common.objects.user.AccessLevel;
import net.jami.jams.common.serialization.adapters.GsonFactory;
import net.jami.jams.common.serialization.tomcat.TomcatCustomErrorHandler;
import net.jami.jams.common.utils.ContactMerger;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
@WebServlet("/api/admin/contacts")
public class ContactServlet extends HttpServlet {
@ -68,8 +62,8 @@ public class ContactServlet extends HttpServlet {
@JsonContent
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
List<Contact> contactList =
dataStore.getContactDao().getByOwner(req.getParameter("username"));
String username = req.getParameter("username");
List<Contact> contactList = dataStore.getContactDao().getByOwner(username);
resp.getOutputStream().write(gson.toJson(contactList).getBytes());
}
@ -90,28 +84,9 @@ public class ContactServlet extends HttpServlet {
@ScopedServletMethod(securityGroups = {AccessLevel.ADMIN})
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Scanner s = new Scanner(req.getInputStream()).useDelimiter("\\A");
String res = s.hasNext() ? s.next() : "";
final JSONObject obj = new JSONObject(res);
Contact contact = new Contact();
// TODO: Replace with mergetool.
contact.setDisplayName(obj.get("displayName").toString());
contact.setTimestamp(System.currentTimeMillis() / 1000);
contact.setStatus('A');
contact.setOwner(req.getParameter("username"));
contact.setUri(obj.get("uri").toString());
List<Contact> localList =
dataStore.getContactDao().getByOwner(req.getParameter("username"));
List<Contact> remoteList = new ArrayList<>();
remoteList.add(contact);
List<Contact> result = ContactMerger.mergeContacts(localList, remoteList);
if (dataStore.getContactDao().storeContactList(result)) resp.setStatus(200);
else
TomcatCustomErrorHandler.sendCustomError(
resp, 500, "could not store a contact due to server-side error");
String username = req.getParameter("username");
net.jami.jams.server.servlets.api.auth.contacts.ContactServlet.addContact(
req, resp, username);
}
/**
@ -155,15 +130,8 @@ public class ContactServlet extends HttpServlet {
@ScopedServletMethod(securityGroups = {AccessLevel.ADMIN})
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
List<Contact> localList =
dataStore.getContactDao().getByOwner(req.getParameter("username"));
List<Contact> remoteList = Arrays.asList(gson.fromJson(req.getReader(), Contact[].class));
remoteList.forEach(contact -> contact.setOwner(req.getParameter("username")));
List<Contact> result = ContactMerger.mergeContacts(localList, remoteList);
if (!dataStore.getContactDao().storeContactList(result))
TomcatCustomErrorHandler.sendCustomError(resp, 500, "Could not store contacts!");
else resp.getOutputStream().write(gson.toJson(result).getBytes());
String username = req.getParameter("username");
net.jami.jams.server.servlets.api.auth.contacts.ContactServlet.addContacts(
req, resp, username);
}
}

View File

@ -23,6 +23,7 @@
package net.jami.jams.server.servlets.api.admin.update;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
@ -38,8 +39,6 @@ import net.jami.jams.common.serialization.adapters.GsonFactory;
import net.jami.jams.server.Server;
import net.jami.jams.server.licensing.LicenseService;
import org.json.JSONObject;
import java.io.FileWriter;
import java.io.IOException;
@ -68,22 +67,18 @@ public class SubscriptionServlet extends HttpServlet {
@ScopedServletMethod(securityGroups = {AccessLevel.ADMIN})
@JsonContent
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String license = new String(req.getInputStream().readAllBytes());
final JSONObject obj = new JSONObject(license);
license = obj.getString("base64License");
JsonObject jsonObject = gson.fromJson(req.getReader(), JsonObject.class);
String license = jsonObject.get("base64License").getAsString();
if (license != null || !license.isBlank()) {
// create .dat file to be used later
FileWriter fw = new FileWriter("license.dat");
fw.write(license);
fw.close();
LicenseService licenseService = new LicenseService();
licenseService.loadLicense();
if (Server.activated.get()) {
resp.setStatus(200);
return;
}
// create .dat file to be used later
FileWriter fw = new FileWriter("license.dat");
fw.write(license);
fw.close();
LicenseService licenseService = new LicenseService();
licenseService.loadLicense();
if (Server.activated.get()) {
resp.setStatus(200);
}
resp.setStatus(500);
}
}

View File

@ -37,7 +37,6 @@ import lombok.extern.slf4j.Slf4j;
import net.jami.jams.common.authentication.AuthenticationSourceType;
import net.jami.jams.common.authmodule.AuthModuleKey;
import net.jami.jams.common.objects.user.User;
import net.jami.jams.common.objects.user.UserProfile;
import net.jami.jams.common.serialization.adapters.GsonFactory;
@ -203,55 +202,49 @@ public class DirectoryEntryServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String directory = req.getParameter("directory");
String directoryType = req.getParameter("directoryType");
String format = req.getParameter("format");
boolean isInVCardFormat = format != null && format.equals("vcard");
String jamiId = req.getParameter("jamiId");
if (jamiId != null) {
User user = dataStore.getUserDao().getByJamiId(jamiId).get(0);
List<UserProfile> userProfiles = new ArrayList<>();
userAuthenticationModule
.getAuthSources()
.forEach(
(k, v) -> {
userProfiles.addAll(
v.searchUserProfiles(
user.getUsername(),
"LOGON_NAME",
Optional.empty()));
});
if (req.getParameter("format") != null && req.getParameter("format").equals("vcard")) {
resp.getOutputStream().write(userProfiles.get(0).getAsVCard().getBytes());
} else resp.getOutputStream().write(gson.toJson(userProfiles.get(0)).getBytes());
return;
}
if (req.getParameter("directory") != null && req.getParameter("directoryType") != null) {
List<UserProfile> profiles =
String username =
jamiId != null
? dataStore.getUserDao().getByJamiId(jamiId).get(0).getUsername()
: req.getParameter("username");
if (directory != null && directoryType != null) {
AuthModuleKey authModuleKey =
new AuthModuleKey(
directory, AuthenticationSourceType.fromString(directoryType));
List<UserProfile> userProfiles =
userAuthenticationModule
.getAuthSources()
.get(
new AuthModuleKey(
req.getParameter("directory"),
AuthenticationSourceType.fromString(
req.getParameter("directoryType"))))
.searchUserProfiles(
req.getParameter("username"), "LOGON_NAME", Optional.empty());
if (req.getParameter("format") != null && req.getParameter("format").equals("vcard")) {
resp.getOutputStream().write(profiles.get(0).getAsVCard().getBytes());
} else resp.getOutputStream().write(gson.toJson(profiles.get(0)).getBytes());
.get(authModuleKey)
.searchUserProfiles(username, "LOGON_NAME", Optional.empty());
UserProfile userProfile = userProfiles.get(0);
String result = isInVCardFormat ? userProfile.getAsVCard() : gson.toJson(userProfile);
resp.getOutputStream().write(result.getBytes());
return;
}
List<UserProfile> userProfiles = new ArrayList<>();
userAuthenticationModule
.getAuthSources()
.values()
.forEach(
(k, v) -> {
v -> {
userProfiles.addAll(
v.searchUserProfiles(
req.getParameter("username"),
"LOGON_NAME",
Optional.empty()));
v.searchUserProfiles(username, "LOGON_NAME", Optional.empty()));
});
if (req.getParameter("format") != null && req.getParameter("format").equals("vcard")) {
resp.getOutputStream().write(userProfiles.get(0).getAsVCard().getBytes());
} else resp.getOutputStream().write(gson.toJson(userProfiles.get(0)).getBytes());
UserProfile userProfile = userProfiles.get(0);
String result = isInVCardFormat ? userProfile.getAsVCard() : gson.toJson(userProfile);
resp.getOutputStream().write(result.getBytes());
}
@Override

View File

@ -1,5 +1,7 @@
package net.jami.jams.server.servlets.api.image;
import com.google.gson.Gson;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
@ -9,6 +11,7 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import lombok.extern.slf4j.Slf4j;
import net.jami.jams.common.serialization.adapters.GsonFactory;
import java.io.File;
@ -20,8 +23,6 @@ import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.Gson;
@MultipartConfig
@Slf4j
@WebServlet("/api/image/filehandler/*")
@ -87,7 +88,8 @@ public class FileHandlerServlet extends HttpServlet {
}
Map<String, String> map = new HashMap<>();
String url = "/api/image/filehandler/" + blueprintName + "/" + imageType + "/" + fileName;
String url =
"/api/image/filehandler/" + blueprintName + "/" + imageType + "/" + fileName;
map.put("url", url);
Gson gson = GsonFactory.createGson();

View File

@ -95,9 +95,7 @@ public class FilterUtils {
}
String username = token.getJWTClaimsSet().getSubject();
log.info("Getting user from database");
User user = dataStore.getUserDao().getByUsername(username).orElseThrow();
log.info("User retrieved from database: {}", user);
if (!user.getAccessLevelName().equals("ADMIN")
&& certificateAuthority.getLatestCRL().get() != null) {

View File

@ -38,7 +38,11 @@ import org.ldaptive.SearchRequest;
import org.ldaptive.SearchResponse;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Slf4j
@ -58,45 +62,23 @@ public class UserProfileService {
queryString.getBytes(StandardCharsets.UTF_8),
StandardCharsets.ISO_8859_1);
connection = connectionFactory.getConnection();
try {
connection.open();
SearchOperation search = new SearchOperation(connectionFactory);
SearchResponse res = search.execute(buildRequest(queryString, field, exactMatch));
connection.open();
SearchOperation search = new SearchOperation(connectionFactory);
SearchResponse res = search.execute(buildRequest(queryString, field, exactMatch));
DataStore.NUM_PAGES =
(Integer) res.getEntries().size() / DataStore.RESULTS_PER_PAGE;
if (res.getEntries().size() % DataStore.RESULTS_PER_PAGE != 0)
DataStore.NUM_PAGES++;
Collection<LdapEntry> entries = getEntriesPage(res, page);
if (page.isPresent() && !res.getEntries().isEmpty()) {
if (res.getEntries().size() < DataStore.RESULTS_PER_PAGE)
res = res.subResult(0, res.getEntries().size());
else if (page.get() * DataStore.RESULTS_PER_PAGE > res.getEntries().size())
res =
res.subResult(
(page.get() - 1) * DataStore.RESULTS_PER_PAGE,
res.getEntries().size());
else
res =
res.subResult(
(page.get() - 1) * DataStore.RESULTS_PER_PAGE,
(page.get() * DataStore.RESULTS_PER_PAGE));
}
if (entries.isEmpty()) return new ArrayList<>();
if (res.getEntries().size() == 0) return new ArrayList<>();
List<UserProfile> profilesFromResponse =
res.getEntries().stream()
.map(UserProfileService::profileFromResponse)
.collect(Collectors.toList());
for (UserProfile p : profilesFromResponse) {
dataStore.getUserProfileDao().insertIfNotExists(p);
}
return profilesFromResponse;
} catch (Exception e) {
log.error("Could not search LDAP directory with error " + e);
return null;
List<UserProfile> profilesFromResponse =
entries.stream()
.map(UserProfileService::profileFromResponse)
.collect(Collectors.toList());
for (UserProfile p : profilesFromResponse) {
dataStore.getUserProfileDao().insertIfNotExists(p);
}
return profilesFromResponse;
} catch (Exception e) {
log.info("Failed to search LDAP directory with error " + e);
return null;
@ -105,6 +87,28 @@ public class UserProfileService {
}
}
private Collection<LdapEntry> getEntriesPage(SearchResponse res, Optional<Integer> page) {
int size = res.getEntries().size();
DataStore.NUM_PAGES = (Integer) size / DataStore.RESULTS_PER_PAGE;
if (size % DataStore.RESULTS_PER_PAGE != 0) DataStore.NUM_PAGES++;
if (page.isEmpty() || size == 0) {
return res.getEntries();
}
if (size < DataStore.RESULTS_PER_PAGE) res = res.subResult(0, size);
else if (page.get() * DataStore.RESULTS_PER_PAGE > size)
res = res.subResult((page.get() - 1) * DataStore.RESULTS_PER_PAGE, size);
else
res =
res.subResult(
(page.get() - 1) * DataStore.RESULTS_PER_PAGE,
(page.get() * DataStore.RESULTS_PER_PAGE));
return res.getEntries();
}
public static SearchRequest buildRequest(String queryString, String field, boolean exactMatch) {
if (!exactMatch) {