updates to validation on all api endpoints
This commit is contained in:
parent
1191713b48
commit
f74ea387d7
@ -1,6 +1,6 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import org.bigbluebutton.api.model.validator.ChecksumValidator;
|
||||
import org.bigbluebutton.api.model.validator.GetChecksumValidator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
@ -10,10 +10,10 @@ import java.lang.annotation.Target;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Constraint(validatedBy = ChecksumValidator.class)
|
||||
@Constraint(validatedBy = GetChecksumValidator.class)
|
||||
@Target(TYPE)
|
||||
@Retention(RUNTIME)
|
||||
public @interface ChecksumConstraint {
|
||||
public @interface GetChecksumConstraint {
|
||||
|
||||
String message() default "Invalid checksum: checksums do not match";
|
||||
Class<?>[] groups() default {};
|
@ -0,0 +1,21 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import org.bigbluebutton.api.model.validator.GuestPolicyValidator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Constraint(validatedBy = { GuestPolicyValidator.class })
|
||||
@Target(FIELD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface GuestPolicyConstraint {
|
||||
|
||||
String message() default "User denied access for this session";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import org.bigbluebutton.api.model.validator.MaxParticipantsValidator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Constraint(validatedBy = { MaxParticipantsValidator.class })
|
||||
@Target(FIELD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface MaxParticipantsConstraint {
|
||||
|
||||
String message() default "The maximum number of participants for the meeting has been reached";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import org.bigbluebutton.api.model.validator.MeetingEndedValidator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Constraint(validatedBy = MeetingEndedValidator.class)
|
||||
@Target(FIELD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface MeetingEndedConstraint {
|
||||
|
||||
String message() default "You can not re-join a meeting that has already been forcibly ended";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import org.bigbluebutton.api.model.validator.MeetingExistsValidator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Constraint(validatedBy = MeetingExistsValidator.class)
|
||||
@Target(FIELD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface MeetingExistsConstraint {
|
||||
|
||||
String message() default "Invalid meeting ID: A meeting with that ID does not exist";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@NotEmpty(message = "You must provide a meeting ID")
|
||||
@Size(min = 2, max = 256, message = "Meeting ID must be between 2 and 256 characters")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9\\s!@#$%^&*()_\\-+=\\[\\]{};:.'\"<>?\\\\|\\/]+$", message = "Meeting ID cannot contain ','")
|
||||
@Constraint(validatedBy = {})
|
||||
@Target(FIELD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface MeetingIDConstraint {
|
||||
|
||||
String message() default "Invalid meeting ID";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@NotEmpty(message = "You must provide a meeting name")
|
||||
@Size(min = 2, max = 256, message = "Meeting name must be between 2 and 256 characters")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9\\s!@#$%^&*()_\\-+=\\[\\]{};:.'\"<>?\\\\|\\/]+$", message = "Meeting name cannot contain ','")
|
||||
@Constraint(validatedBy = {})
|
||||
@Target(FIELD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface MeetingNameConstraint {
|
||||
|
||||
String message() default "Invalid meeting name";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import org.bigbluebutton.api.model.validator.ModeratorPasswordValidator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Constraint(validatedBy = ModeratorPasswordValidator.class)
|
||||
@Target(TYPE)
|
||||
@Retention(RUNTIME)
|
||||
public @interface ModeratorPasswordConstraint {
|
||||
|
||||
String message() default "Invalid password: The supplied moderator password is incorrect";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@NotEmpty(message = "You must provide your password")
|
||||
@Size(min = 2, max = 64, message = "Password must be between 8 and 20 characters")
|
||||
@Constraint(validatedBy = {})
|
||||
@Target(FIELD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface PasswordConstraint {
|
||||
|
||||
String message() default "Invalid password";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import org.bigbluebutton.api.model.validator.PostChecksumValidator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Constraint(validatedBy = PostChecksumValidator.class)
|
||||
@Target(TYPE)
|
||||
@Retention(RUNTIME)
|
||||
public @interface PostChecksumConstraint {
|
||||
|
||||
String message() default "Invalid checksum: checksums do not match";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.bigbluebutton.api.model.constraint;
|
||||
|
||||
import org.bigbluebutton.api.model.validator.UserSessionValidator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Constraint(validatedBy = { UserSessionValidator.class })
|
||||
@Target(FIELD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface UserSessionConstraint {
|
||||
|
||||
String message() default "Invalid session token";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -1,32 +1,45 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.MeetingNameConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.PasswordConstraint;
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.Map;
|
||||
|
||||
public class CreateMeeting extends Request {
|
||||
public class CreateMeeting extends RequestWithChecksum<CreateMeeting.Params> {
|
||||
|
||||
@NotEmpty(message = "You must provide a meeting name")
|
||||
@Size(min = 2, max = 256, message = "Meeting name must be between 2 and 256 characters")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9\\s!@#$%^&*()_\\-+=\\[\\]{};:.'\"<>?\\\\|\\/]+$", message = "Meeting name cannot contain ','")
|
||||
public enum Params implements RequestParameters {
|
||||
NAME("name"),
|
||||
MEETING_ID("meetingID"),
|
||||
VOICE_BRIDGE("voiceBridge"),
|
||||
ATTENDEE_PW("attendeePW"),
|
||||
MODERATOR_PW("moderatorPW"),
|
||||
IS_BREAKOUT_ROOM("isBreakoutRoom"),
|
||||
RECORD("record");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
@MeetingNameConstraint
|
||||
private String name;
|
||||
|
||||
@NotEmpty(message = "You must provide a meeting ID")
|
||||
@Size(min = 2, max = 256, message = "Meeting ID must be between 2 and 256 characters")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9\\s!@#$%^&*()_\\-+=\\[\\]{};:.'\"<>?\\\\|\\/]+$", message = "Meeting ID cannot contain ','")
|
||||
@MeetingIDConstraint
|
||||
private String meetingID;
|
||||
|
||||
@NotEmpty(message = "You must provide a voice bridge")
|
||||
private String voiceBridge;
|
||||
|
||||
@NotEmpty(message = "You must provide an attendee password")
|
||||
@PasswordConstraint
|
||||
private String attendeePW;
|
||||
|
||||
@NotEmpty(message = "You must provide a moderator password")
|
||||
@PasswordConstraint
|
||||
private String moderatorPW;
|
||||
|
||||
@NotNull(message = "You must provide whether this meeting is breakout room")
|
||||
@ -97,12 +110,12 @@ public class CreateMeeting extends Request {
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey("name")) setName(params.get("name")[0]);
|
||||
if(params.containsKey("meetingID")) setMeetingID(params.get("meetingID")[0]);
|
||||
if(params.containsKey("voiceBridge")) setVoiceBridge(params.get("voiceBridge")[0]);
|
||||
if(params.containsKey("attendeePW")) setAttendeePW(params.get("attendeePW")[0]);
|
||||
if(params.containsKey("moderatorPW")) setModeratorPW(params.get("moderatorPW")[0]);
|
||||
if(params.containsKey("isBreakoutRoom")) setBreakoutRoom(Boolean.parseBoolean(params.get("isBreakoutRoom")[0]));
|
||||
if(params.containsKey("record")) setRecord(Boolean.parseBoolean(params.get("record")[0]));
|
||||
if(params.containsKey(Params.NAME.getValue())) setName(params.get(Params.NAME.getValue())[0]);
|
||||
if(params.containsKey(Params.MEETING_ID.getValue())) setMeetingID(params.get(Params.MEETING_ID.getValue())[0]);
|
||||
if(params.containsKey(Params.VOICE_BRIDGE.getValue())) setVoiceBridge(params.get(Params.VOICE_BRIDGE.getValue())[0]);
|
||||
if(params.containsKey(Params.ATTENDEE_PW.getValue())) setAttendeePW(params.get(Params.ATTENDEE_PW.getValue())[0]);
|
||||
if(params.containsKey(Params.MODERATOR_PW.getValue())) setModeratorPW(params.get(Params.MODERATOR_PW.getValue())[0]);
|
||||
if(params.containsKey(Params.IS_BREAKOUT_ROOM.getValue())) setBreakoutRoom(Boolean.parseBoolean(params.get(Params.IS_BREAKOUT_ROOM.value)[0]));
|
||||
if(params.containsKey(Params.RECORD.getValue())) setRecord(Boolean.parseBoolean(params.get(Params.RECORD.getValue())[0]));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.PasswordConstraint;
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
import org.bigbluebutton.api.model.shared.ModeratorPassword;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Map;
|
||||
|
||||
public class EndMeeting extends RequestWithChecksum<EndMeeting.Params> {
|
||||
|
||||
public enum Params implements RequestParameters {
|
||||
MEETING_ID("meetingID"),
|
||||
PASSWORD("password");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
@MeetingIDConstraint
|
||||
@MeetingExistsConstraint
|
||||
private String meetingID;
|
||||
|
||||
@PasswordConstraint
|
||||
private String password;
|
||||
|
||||
@Valid
|
||||
private ModeratorPassword moderatorPassword;
|
||||
|
||||
public EndMeeting(Checksum checksum) {
|
||||
super(checksum);
|
||||
moderatorPassword = new ModeratorPassword();
|
||||
}
|
||||
|
||||
public String getMeetingID() {
|
||||
return meetingID;
|
||||
}
|
||||
|
||||
public void setMeetingID(String meetingID) {
|
||||
this.meetingID = meetingID;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey(Params.MEETING_ID.getValue())) {
|
||||
setMeetingID(params.get(Params.MEETING_ID.getValue())[0]);
|
||||
moderatorPassword.setMeetingID(meetingID);
|
||||
}
|
||||
|
||||
if(params.containsKey(Params.PASSWORD.getValue())) {
|
||||
setPassword(params.get(Params.PASSWORD.getValue())[0]);
|
||||
moderatorPassword.setPassword(password);
|
||||
}
|
||||
}
|
||||
}
|
52
bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Enter.java
Executable file
52
bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Enter.java
Executable file
@ -0,0 +1,52 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.*;
|
||||
import org.bigbluebutton.api.service.SessionService;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Map;
|
||||
|
||||
public class Enter implements Request<Enter.Params> {
|
||||
|
||||
public enum Params implements RequestParameters {
|
||||
SESSION_TOKEN("sessionToken");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
@NotNull(message = "You must provide a session token")
|
||||
@UserSessionConstraint
|
||||
@MaxParticipantsConstraint
|
||||
@GuestPolicyConstraint
|
||||
private String sessionToken;
|
||||
|
||||
@MeetingExistsConstraint
|
||||
@MeetingEndedConstraint
|
||||
private String meetingID;
|
||||
|
||||
private SessionService sessionService;
|
||||
|
||||
public Enter() {
|
||||
sessionService = new SessionService();
|
||||
}
|
||||
|
||||
public String getSessionToken() {
|
||||
return sessionToken;
|
||||
}
|
||||
|
||||
public void setSessionToken(String sessionToken) {
|
||||
this.sessionToken = sessionToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey(Params.SESSION_TOKEN.getValue())) {
|
||||
setSessionToken(params.get(Params.SESSION_TOKEN.getValue())[0]);
|
||||
sessionService.setSessionToken(sessionToken);
|
||||
meetingID = sessionService.getMeetingID();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.MeetingEndedConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.UserSessionConstraint;
|
||||
import org.bigbluebutton.api.service.SessionService;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Map;
|
||||
|
||||
public class GuestWait implements Request<GuestWait.Params> {
|
||||
|
||||
public enum Params implements RequestParameters {
|
||||
SESSION_TOKEN("sessionToken");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
@NotNull(message = "You must provide the session token")
|
||||
@UserSessionConstraint
|
||||
private String sessionToken;
|
||||
|
||||
@MeetingExistsConstraint
|
||||
@MeetingEndedConstraint
|
||||
private String meetingID;
|
||||
|
||||
private SessionService sessionService;
|
||||
|
||||
public GuestWait() {
|
||||
sessionService = new SessionService();
|
||||
}
|
||||
|
||||
public String getSessionToken() {
|
||||
return sessionToken;
|
||||
}
|
||||
|
||||
public void setSessionToken(String sessionToken) {
|
||||
this.sessionToken = sessionToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey(Params.SESSION_TOKEN.getValue())) {
|
||||
setSessionToken(params.get(Params.SESSION_TOKEN.getValue())[0]);
|
||||
sessionService.setSessionToken(sessionToken);
|
||||
meetingID = sessionService.getMeetingID();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,35 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.MeetingEndedConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.PasswordConstraint;
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.Map;
|
||||
|
||||
public class JoinMeeting extends Request {
|
||||
public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> {
|
||||
|
||||
@NotEmpty(message = "You must provide a meeting ID")
|
||||
@Size(min = 2, max = 256, message = "Meeting ID must be between 2 and 256 characters")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9\\s!@#$%^&*()_\\-+=\\[\\]{};:.'\"<>?\\\\|\\/]+$", message = "Meeting name cannot contain ','")
|
||||
public enum Params implements RequestParameters {
|
||||
MEETING_ID("meetingID"),
|
||||
USER_ID("userID"),
|
||||
FULL_NAME("fullName"),
|
||||
PASSWORD("password"),
|
||||
GUEST("guest"),
|
||||
AUTH("auth"),
|
||||
CREATE_TIME("createTime");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
@MeetingIDConstraint
|
||||
@MeetingExistsConstraint
|
||||
@MeetingEndedConstraint
|
||||
private String meetingID;
|
||||
|
||||
private String userID;
|
||||
@ -20,8 +37,7 @@ public class JoinMeeting extends Request {
|
||||
@NotEmpty(message = "You must provide your name")
|
||||
private String fullName;
|
||||
|
||||
@NotEmpty(message = "You must provide your password")
|
||||
@Size(min = 2, max = 64, message = "Password must be between 8 and 20 characters")
|
||||
@PasswordConstraint
|
||||
private String password;
|
||||
|
||||
private Boolean guest;
|
||||
@ -92,12 +108,15 @@ public class JoinMeeting extends Request {
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey("meetingID")) setMeetingID(params.get("meetingID")[0]);
|
||||
if(params.containsKey("userID")) setUserID(params.get("userID")[0]);
|
||||
if(params.containsKey("fullName")) setFullName(params.get("fullName")[0]);
|
||||
if(params.containsKey("password")) setPassword(params.get("password")[0]);
|
||||
if(params.containsKey("guest")) setGuest(Boolean.parseBoolean(params.get("guest")[0]));
|
||||
if(params.containsKey("auth")) setAuth(Boolean.parseBoolean(params.get("auth")[0]));
|
||||
if(params.containsKey("createTime")) setCreateTime(Long.parseLong(params.get("createTime")[0]));
|
||||
if(params.containsKey(Params.MEETING_ID.getValue())) {
|
||||
setMeetingID(params.get(Params.MEETING_ID.getValue())[0]);
|
||||
}
|
||||
|
||||
if(params.containsKey(Params.USER_ID.getValue())) setUserID(params.get(Params.USER_ID.getValue())[0]);
|
||||
if(params.containsKey(Params.FULL_NAME.getValue())) setFullName(params.get(Params.FULL_NAME.getValue())[0]);
|
||||
if(params.containsKey(Params.PASSWORD.getValue())) setPassword(params.get(Params.PASSWORD.getValue())[0]);
|
||||
if(params.containsKey(Params.GUEST.getValue())) setGuest(Boolean.parseBoolean(params.get(Params.GUEST.getValue())[0]));
|
||||
if(params.containsKey(Params.AUTH.getValue())) setAuth(Boolean.parseBoolean(params.get(Params.AUTH.getValue())[0]));
|
||||
if(params.containsKey(Params.CREATE_TIME.getValue())) setCreateTime(Long.parseLong(params.get(Params.CREATE_TIME.getValue())[0]));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class MeetingInfo extends RequestWithChecksum<MeetingInfo.Params> {
|
||||
|
||||
public enum Params implements RequestParameters {
|
||||
MEETING_ID("meetingID");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
@MeetingIDConstraint
|
||||
@MeetingExistsConstraint
|
||||
private String meetingID;
|
||||
|
||||
public MeetingInfo(Checksum checksum) {
|
||||
super(checksum);
|
||||
}
|
||||
|
||||
public String getMeetingID() {
|
||||
return meetingID;
|
||||
}
|
||||
|
||||
public void setMeetingID(String meetingID) {
|
||||
this.meetingID = meetingID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey(Params.MEETING_ID.getValue())) {
|
||||
setMeetingID(params.get(Params.MEETING_ID.getValue())[0]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class MeetingRunning extends RequestWithChecksum<MeetingRunning.Params> {
|
||||
|
||||
public enum Params implements RequestParameters {
|
||||
MEETING_ID("meetingID");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
@MeetingIDConstraint
|
||||
private String meetingID;
|
||||
|
||||
public MeetingRunning(Checksum checksum) {
|
||||
super(checksum);
|
||||
}
|
||||
|
||||
public String getMeetingID() {
|
||||
return meetingID;
|
||||
}
|
||||
|
||||
public void setMeetingID(String meetingID) {
|
||||
this.meetingID = meetingID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey(Params.MEETING_ID.getValue())) setMeetingID(params.get(Params.MEETING_ID.getValue())[0]);
|
||||
}
|
||||
}
|
@ -1,26 +1,8 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class Request {
|
||||
public interface Request<P extends Enum<P> & RequestParameters> {
|
||||
|
||||
@Valid
|
||||
protected Checksum checksum;
|
||||
|
||||
protected Request(Checksum checksum) {
|
||||
this.checksum = checksum;
|
||||
}
|
||||
|
||||
public Checksum getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
public void setChecksum(Checksum checksum) {
|
||||
this.checksum = checksum;
|
||||
}
|
||||
|
||||
public abstract void populateFromParamsMap(Map<String, String[]> params);
|
||||
void populateFromParamsMap(Map<String, String[]> params);
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
public interface RequestParameters {
|
||||
|
||||
String getValue();
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class RequestWithChecksum<P extends Enum<P> & RequestParameters> implements Request<P> {
|
||||
|
||||
@Valid
|
||||
protected Checksum checksum;
|
||||
|
||||
protected RequestWithChecksum(Checksum checksum) {
|
||||
this.checksum = checksum;
|
||||
}
|
||||
|
||||
public Checksum getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
public void setChecksum(Checksum checksum) {
|
||||
this.checksum = checksum;
|
||||
}
|
||||
|
||||
public abstract void populateFromParamsMap(Map<String, String[]> params);
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint;
|
||||
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.Map;
|
||||
|
||||
public class SetPollXML extends RequestWithChecksum<SetPollXML.Params> {
|
||||
|
||||
public enum Params implements RequestParameters {
|
||||
MEETING_ID("meetingID"),
|
||||
POLL_XML("pollXML");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
@MeetingIDConstraint
|
||||
@MeetingExistsConstraint
|
||||
private String meetingID;
|
||||
|
||||
@NotEmpty(message = "You must provide the poll")
|
||||
private String pollXML;
|
||||
|
||||
public SetPollXML(Checksum checksum) {
|
||||
super(checksum);
|
||||
}
|
||||
|
||||
public String getMeetingID() {
|
||||
return meetingID;
|
||||
}
|
||||
|
||||
public void setMeetingID(String meetingID) {
|
||||
this.meetingID = meetingID;
|
||||
}
|
||||
|
||||
public String getPollXML() {
|
||||
return pollXML;
|
||||
}
|
||||
|
||||
public void setPollXML(String pollXML) {
|
||||
this.pollXML = pollXML;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey(Params.MEETING_ID.getValue())) {
|
||||
setMeetingID(params.get(Params.MEETING_ID.getValue())[0]);
|
||||
}
|
||||
|
||||
if(params.containsKey(Params.POLL_XML.getValue())) setPollXML(params.get(Params.POLL_XML.getValue())[0]);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.UserSessionConstraint;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Map;
|
||||
|
||||
public class SignOut implements Request<SignOut.Params> {
|
||||
|
||||
public enum Params implements RequestParameters {
|
||||
SESSION_TOKEN("sessionToken");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
@NotNull(message = "You must provide a session token")
|
||||
@UserSessionConstraint
|
||||
private String sessionToken;
|
||||
|
||||
public String getSessionToken() {
|
||||
return sessionToken;
|
||||
}
|
||||
|
||||
public void setSessionToken(String sessionToken) {
|
||||
this.sessionToken = sessionToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey(Enter.Params.SESSION_TOKEN.getValue())) setSessionToken(params.get(Enter.Params.SESSION_TOKEN.getValue())[0]);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SimpleRequest extends RequestWithChecksum<SimpleRequest.Params> {
|
||||
|
||||
public enum Params implements RequestParameters {
|
||||
NONE("none");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
public SimpleRequest(Checksum checksum) {
|
||||
super(checksum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {}
|
||||
}
|
50
bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Stuns.java
Executable file
50
bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Stuns.java
Executable file
@ -0,0 +1,50 @@
|
||||
package org.bigbluebutton.api.model.request;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.*;
|
||||
import org.bigbluebutton.api.service.SessionService;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Map;
|
||||
|
||||
public class Stuns implements Request<Stuns.Params> {
|
||||
|
||||
public enum Params implements RequestParameters {
|
||||
SESSION_TOKEN("sessionToken");
|
||||
|
||||
private final String value;
|
||||
|
||||
Params(String value) { this.value = value; }
|
||||
|
||||
public String getValue() { return value; }
|
||||
}
|
||||
|
||||
@NotNull(message = "You must provide a session token")
|
||||
@UserSessionConstraint
|
||||
private String sessionToken;
|
||||
|
||||
@MeetingExistsConstraint
|
||||
@MeetingEndedConstraint
|
||||
private String meetingID;
|
||||
|
||||
private SessionService sessionService;
|
||||
|
||||
public Stuns() { sessionService = new SessionService(); }
|
||||
|
||||
public String getSessionToken() {
|
||||
return sessionToken;
|
||||
}
|
||||
|
||||
public void setSessionToken(String sessionToken) {
|
||||
this.sessionToken = sessionToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey(Enter.Params.SESSION_TOKEN.getValue())) {
|
||||
setSessionToken(params.get(Enter.Params.SESSION_TOKEN.getValue())[0]);
|
||||
sessionService.setSessionToken(sessionToken);
|
||||
meetingID = sessionService.getMeetingID();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +1,22 @@
|
||||
package org.bigbluebutton.api.model.shared;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.bigbluebutton.api.model.constraint.ChecksumConstraint;
|
||||
import org.bigbluebutton.api.util.ParamsUtil;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@ChecksumConstraint(message = "Checksums do not match")
|
||||
public class Checksum {
|
||||
public abstract class Checksum {
|
||||
|
||||
@NotEmpty(message = "You must provide the API call")
|
||||
private String apiCall;
|
||||
protected String apiCall;
|
||||
|
||||
@NotEmpty(message = "You must provide the checksum")
|
||||
private String checksum;
|
||||
protected String checksum;
|
||||
|
||||
@NotEmpty(message = "You must provide the query string")
|
||||
private String queryString;
|
||||
protected String queryStringWithoutChecksum;
|
||||
|
||||
private String queryStringWithoutChecksum;
|
||||
|
||||
public Checksum(String apiCall, String checksum, String queryString) {
|
||||
public Checksum(String apiCall, String checksum) {
|
||||
this.apiCall = ParamsUtil.sanitizeString(apiCall);
|
||||
this.checksum = ParamsUtil.sanitizeString(checksum);
|
||||
this.queryString = ParamsUtil.sanitizeString(queryString);
|
||||
removeChecksumFromQueryString();
|
||||
}
|
||||
|
||||
private void removeChecksumFromQueryString() {
|
||||
List<NameValuePair> params = URLEncodedUtils.parse(queryString, StandardCharsets.UTF_8);
|
||||
|
||||
Iterator<NameValuePair> itr = params.iterator();
|
||||
while(itr.hasNext()) {
|
||||
NameValuePair pair = itr.next();
|
||||
if(pair.getName().equals("checksum")) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
|
||||
queryStringWithoutChecksum = URLEncodedUtils.format(params, '&', StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public String getApiCall() {
|
||||
@ -61,14 +35,6 @@ public class Checksum {
|
||||
this.checksum = checksum;
|
||||
}
|
||||
|
||||
public String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
public void setQueryString(String queryString) {
|
||||
this.queryString = queryString;
|
||||
}
|
||||
|
||||
public String getQueryStringWithoutChecksum() {
|
||||
return queryStringWithoutChecksum;
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
package org.bigbluebutton.api.model.shared;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.bigbluebutton.api.model.constraint.GetChecksumConstraint;
|
||||
import org.bigbluebutton.api.util.ParamsUtil;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@GetChecksumConstraint(message = "Checksums do not match")
|
||||
public class GetChecksum extends Checksum {
|
||||
|
||||
@NotEmpty(message = "You must provide the query string")
|
||||
private String queryString;
|
||||
|
||||
public GetChecksum(String apiCall, String checksum, String queryString) {
|
||||
super(apiCall, checksum);
|
||||
this.queryString = ParamsUtil.sanitizeString(queryString);
|
||||
removeChecksumFromQueryString();
|
||||
}
|
||||
|
||||
private void removeChecksumFromQueryString() {
|
||||
List<NameValuePair> params = URLEncodedUtils.parse(queryString, StandardCharsets.UTF_8);
|
||||
|
||||
Iterator<NameValuePair> itr = params.iterator();
|
||||
while(itr.hasNext()) {
|
||||
NameValuePair pair = itr.next();
|
||||
if(pair.getName().equals("checksum")) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
|
||||
queryStringWithoutChecksum = URLEncodedUtils.format(params, '&', StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
public void setQueryString(String queryString) {
|
||||
this.queryString = queryString;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.bigbluebutton.api.model.shared;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.ModeratorPasswordConstraint;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
@ModeratorPasswordConstraint(message = "Provided moderator password is incorrect")
|
||||
public class ModeratorPassword {
|
||||
|
||||
@NotEmpty(message = "You must provide the meeting ID")
|
||||
private String meetingID;
|
||||
|
||||
@NotEmpty(message = "You must provide the password for the call")
|
||||
private String password;
|
||||
|
||||
public String getMeetingID() {
|
||||
return meetingID;
|
||||
}
|
||||
|
||||
public void setMeetingID(String meetingID) {
|
||||
this.meetingID = meetingID;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package org.bigbluebutton.api.model.shared;
|
||||
|
||||
import org.bigbluebutton.api.model.constraint.PostChecksumConstraint;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
@PostChecksumConstraint(message = "Checksums do not match")
|
||||
public class PostChecksum extends Checksum {
|
||||
|
||||
Map<String, String[]> params;
|
||||
|
||||
public PostChecksum(String apiCall, String checksum, Map<String, String[]> params) {
|
||||
super(apiCall, checksum);
|
||||
this.params = params;
|
||||
buildQueryStringFromParamsMap();
|
||||
}
|
||||
|
||||
private void buildQueryStringFromParamsMap() {
|
||||
StringBuilder queryString = new StringBuilder();
|
||||
SortedSet<String> keys = new TreeSet<>(params.keySet());
|
||||
|
||||
boolean firstParam = true;
|
||||
for(String key: keys) {
|
||||
|
||||
if(key.equals("checksum")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(String value: params.get(key)) {
|
||||
if(firstParam) {
|
||||
firstParam = false;
|
||||
} else {
|
||||
queryString.append("&");
|
||||
}
|
||||
|
||||
queryString.append(key);
|
||||
queryString.append("=");
|
||||
|
||||
String encodedValue = encodeString(value);
|
||||
queryString.append(encodedValue);
|
||||
}
|
||||
}
|
||||
|
||||
queryStringWithoutChecksum = queryString.toString();
|
||||
}
|
||||
|
||||
private String encodeString(String stringToEncode) {
|
||||
String encodedResult;
|
||||
|
||||
try {
|
||||
encodedResult = URLEncoder.encode(stringToEncode, StandardCharsets.UTF_8.name());
|
||||
} catch(UnsupportedEncodingException ex) {
|
||||
encodedResult = stringToEncode;
|
||||
}
|
||||
|
||||
return encodedResult;
|
||||
}
|
||||
|
||||
public Map<String, String[]> getParams() { return params; }
|
||||
|
||||
public void setParams(Map<String, String[]> params) { this.params = params; }
|
||||
}
|
@ -4,31 +4,42 @@ import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
import org.bigbluebutton.api.model.constraint.ChecksumConstraint;
|
||||
import org.bigbluebutton.api.service.ValidatorService;
|
||||
import org.bigbluebutton.api.model.constraint.GetChecksumConstraint;
|
||||
import org.bigbluebutton.api.model.shared.GetChecksum;
|
||||
import org.bigbluebutton.api.service.ServiceUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ChecksumValidator implements ConstraintValidator<ChecksumConstraint, Checksum> {
|
||||
public class GetChecksumValidator implements ConstraintValidator<GetChecksumConstraint, GetChecksum> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(ChecksumValidator.class);
|
||||
private static Logger log = LoggerFactory.getLogger(GetChecksumValidator.class);
|
||||
|
||||
@Override
|
||||
public void initialize(ChecksumConstraint checksumConstraint) {}
|
||||
public void initialize(GetChecksumConstraint checksumConstraint) {}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Checksum checksum, ConstraintValidatorContext context) {
|
||||
String securitySalt = ValidatorService.getSecuritySalt();
|
||||
public boolean isValid(GetChecksum checksum, ConstraintValidatorContext context) {
|
||||
String securitySalt = ServiceUtils.getValidationService().getSecuritySalt();
|
||||
|
||||
log.info("Security salt: {}", securitySalt);
|
||||
if (securitySalt.isEmpty()) {
|
||||
log.warn("Security is disabled in this service. Make sure this is intentional.");
|
||||
return true;
|
||||
}
|
||||
|
||||
String queryStringWithoutChecksum = checksum.getQueryStringWithoutChecksum();
|
||||
log.info("query string after checksum removed: [{}]", queryStringWithoutChecksum);
|
||||
|
||||
if(queryStringWithoutChecksum == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String providedChecksum = checksum.getChecksum();
|
||||
log.info("CHECKSUM={} length={}", providedChecksum, providedChecksum.length());
|
||||
|
||||
if(providedChecksum == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String data = checksum.getApiCall() + queryStringWithoutChecksum + securitySalt;
|
||||
String createdCheckSum = DigestUtils.sha1Hex(data);
|
||||
|
@ -0,0 +1,33 @@
|
||||
package org.bigbluebutton.api.model.validator;
|
||||
|
||||
import org.bigbluebutton.api.MeetingService;
|
||||
import org.bigbluebutton.api.domain.GuestPolicy;
|
||||
import org.bigbluebutton.api.domain.UserSession;
|
||||
import org.bigbluebutton.api.model.constraint.GuestPolicyConstraint;
|
||||
import org.bigbluebutton.api.service.ServiceUtils;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
public class GuestPolicyValidator implements ConstraintValidator<GuestPolicyConstraint, String> {
|
||||
|
||||
@Override
|
||||
public void initialize(GuestPolicyConstraint constraintAnnotation) {}
|
||||
|
||||
@Override
|
||||
public boolean isValid(String sessionToken, ConstraintValidatorContext constraintValidatorContext) {
|
||||
|
||||
if(sessionToken == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MeetingService meetingService = ServiceUtils.getMeetingService();
|
||||
UserSession userSession = meetingService.getUserSessionWithAuthToken(sessionToken);
|
||||
|
||||
if(userSession == null || userSession.guestStatus.equals(GuestPolicy.DENY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package org.bigbluebutton.api.model.validator;
|
||||
|
||||
import org.bigbluebutton.api.MeetingService;
|
||||
import org.bigbluebutton.api.domain.Meeting;
|
||||
import org.bigbluebutton.api.domain.UserSession;
|
||||
import org.bigbluebutton.api.model.constraint.MaxParticipantsConstraint;
|
||||
import org.bigbluebutton.api.service.ServiceUtils;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
public class MaxParticipantsValidator implements ConstraintValidator<MaxParticipantsConstraint, String> {
|
||||
|
||||
@Override
|
||||
public void initialize(MaxParticipantsConstraint constraintAnnotation) {}
|
||||
|
||||
@Override
|
||||
public boolean isValid(String sessionToken, ConstraintValidatorContext constraintValidatorContext) {
|
||||
|
||||
if(sessionToken == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MeetingService meetingService = ServiceUtils.getMeetingService();
|
||||
UserSession userSession = meetingService.getUserSessionWithAuthToken(sessionToken);
|
||||
|
||||
if(userSession == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Meeting meeting = meetingService.getMeeting(userSession.meetingID);
|
||||
|
||||
if(meeting == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int maxParticipants = meeting.getMaxUsers();
|
||||
boolean enabled = maxParticipants > 0;
|
||||
boolean rejoin = meeting.getUserById(userSession.internalUserId) != null;
|
||||
boolean reenter = meeting.getEnteredUserById(userSession.internalUserId) != null;
|
||||
int joinedUsers = meeting.getUsers().size();
|
||||
int enteredUsers = meeting.getEnteredUsers().size();
|
||||
|
||||
boolean reachedMax = (joinedUsers + enteredUsers) >= maxParticipants;
|
||||
if(enabled && !rejoin && !reenter && reachedMax) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.bigbluebutton.api.model.validator;
|
||||
|
||||
import org.bigbluebutton.api.domain.Meeting;
|
||||
import org.bigbluebutton.api.model.constraint.MeetingEndedConstraint;
|
||||
import org.bigbluebutton.api.service.ServiceUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
public class MeetingEndedValidator implements ConstraintValidator<MeetingEndedConstraint, String> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(MeetingEndedValidator.class);
|
||||
|
||||
@Override
|
||||
public void initialize(MeetingEndedConstraint constraintAnnotation) {}
|
||||
|
||||
@Override
|
||||
public boolean isValid(String meetingID, ConstraintValidatorContext context) {
|
||||
|
||||
if(meetingID == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Meeting meeting = ServiceUtils.findMeetingFromMeetingID(meetingID);
|
||||
|
||||
if(meeting == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !meeting.isForciblyEnded();
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package org.bigbluebutton.api.model.validator;
|
||||
|
||||
import org.bigbluebutton.api.domain.Meeting;
|
||||
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint;
|
||||
import org.bigbluebutton.api.service.ServiceUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
public class MeetingExistsValidator implements ConstraintValidator<MeetingExistsConstraint, String> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(MeetingExistsValidator.class);
|
||||
|
||||
@Override
|
||||
public void initialize(MeetingExistsConstraint constraintAnnotation) {}
|
||||
|
||||
@Override
|
||||
public boolean isValid(String meetingID, ConstraintValidatorContext context) {
|
||||
log.info("Validating existence of meeting with ID {}", meetingID);
|
||||
|
||||
if(meetingID == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Meeting meeting = ServiceUtils.findMeetingFromMeetingID(meetingID);
|
||||
|
||||
if(meeting == null) {
|
||||
log.info("meetingExistsError: No meeting with the given ID {} could be found", meetingID);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package org.bigbluebutton.api.model.validator;
|
||||
|
||||
import org.bigbluebutton.api.domain.Meeting;
|
||||
import org.bigbluebutton.api.model.constraint.ModeratorPasswordConstraint;
|
||||
import org.bigbluebutton.api.model.shared.ModeratorPassword;
|
||||
import org.bigbluebutton.api.service.ServiceUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
public class ModeratorPasswordValidator implements ConstraintValidator<ModeratorPasswordConstraint, ModeratorPassword> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(MeetingExistsValidator.class);
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize(ModeratorPasswordConstraint constraintAnnotation) {}
|
||||
|
||||
@Override
|
||||
public boolean isValid(ModeratorPassword moderatorPassword, ConstraintValidatorContext context) {
|
||||
log.info("Validating password {} for meeting with ID {}",
|
||||
moderatorPassword.getPassword(), moderatorPassword.getMeetingID());
|
||||
|
||||
if(moderatorPassword.getMeetingID() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Meeting meeting = ServiceUtils.findMeetingFromMeetingID(moderatorPassword.getMeetingID());
|
||||
|
||||
if(meeting == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String actualPassword = meeting.getModeratorPassword();
|
||||
String providedPassword = moderatorPassword.getPassword();
|
||||
|
||||
if(providedPassword == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("Actual password: {}", actualPassword);
|
||||
log.info("Provided password: {}", providedPassword);
|
||||
|
||||
if(!providedPassword.equals(actualPassword)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package org.bigbluebutton.api.model.validator;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.bigbluebutton.api.model.constraint.PostChecksumConstraint;
|
||||
import org.bigbluebutton.api.model.shared.PostChecksum;
|
||||
import org.bigbluebutton.api.service.ServiceUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
public class PostChecksumValidator implements ConstraintValidator<PostChecksumConstraint, PostChecksum> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(PostChecksumValidator.class);
|
||||
|
||||
@Override
|
||||
public void initialize(PostChecksumConstraint constraintAnnotation) {}
|
||||
|
||||
@Override
|
||||
public boolean isValid(PostChecksum checksum, ConstraintValidatorContext context) {
|
||||
String securitySalt = ServiceUtils.getValidationService().getSecuritySalt();
|
||||
|
||||
if (securitySalt.isEmpty()) {
|
||||
log.warn("Security is disabled in this service. Make sure this is intentional.");
|
||||
return true;
|
||||
}
|
||||
|
||||
String queryStringWithoutChecksum = checksum.getQueryStringWithoutChecksum();
|
||||
log.info("query string after checksum removed: [{}]", queryStringWithoutChecksum);
|
||||
|
||||
if(queryStringWithoutChecksum == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String providedChecksum = checksum.getChecksum();
|
||||
log.info("CHECKSUM={} length={}", providedChecksum, providedChecksum.length());
|
||||
|
||||
if(providedChecksum == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String data = checksum.getApiCall() + queryStringWithoutChecksum + securitySalt;
|
||||
String createdCheckSum = DigestUtils.sha1Hex(data);
|
||||
|
||||
if (createdCheckSum == null || !createdCheckSum.equals(checksum)) {
|
||||
log.info("checksumError: failed checksum. our checksum: [{}], client: [{}]", createdCheckSum, checksum);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.bigbluebutton.api.model.validator;
|
||||
|
||||
import org.bigbluebutton.api.domain.UserSession;
|
||||
import org.bigbluebutton.api.model.constraint.UserSessionConstraint;
|
||||
import org.bigbluebutton.api.service.ServiceUtils;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
public class UserSessionValidator implements ConstraintValidator<UserSessionConstraint, String> {
|
||||
|
||||
@Override
|
||||
public void initialize(UserSessionConstraint constraintAnnotation) {}
|
||||
|
||||
@Override
|
||||
public boolean isValid(String sessionToken, ConstraintValidatorContext constraintValidatorContext) {
|
||||
UserSession userSession = ServiceUtils.getMeetingService().getUserSessionWithAuthToken(sessionToken);
|
||||
|
||||
if(userSession == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
39
bbb-common-web/src/main/java/org/bigbluebutton/api/service/ServiceUtils.java
Executable file
39
bbb-common-web/src/main/java/org/bigbluebutton/api/service/ServiceUtils.java
Executable file
@ -0,0 +1,39 @@
|
||||
package org.bigbluebutton.api.service;
|
||||
|
||||
import org.bigbluebutton.api.MeetingService;
|
||||
import org.bigbluebutton.api.ParamsProcessorUtil;
|
||||
import org.bigbluebutton.api.domain.Meeting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ServiceUtils {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(ServiceUtils.class);
|
||||
|
||||
private static MeetingService meetingService;
|
||||
private static ValidationService validationService;
|
||||
|
||||
public void setMeetingService(MeetingService meetingService) { this.meetingService = meetingService; }
|
||||
public static MeetingService getMeetingService() { return meetingService; }
|
||||
|
||||
public void setValidationService(ValidationService validationService) { this.validationService = validationService; }
|
||||
public static ValidationService getValidationService() { return validationService; }
|
||||
|
||||
public static Meeting findMeetingFromMeetingID(String meetingID) {
|
||||
log.info("Attempting to find meeting with ID {}", meetingID);
|
||||
Meeting meeting = meetingService.getMeeting(meetingID);
|
||||
|
||||
if(meeting == null) {
|
||||
log.info("Meeting with ID {} could not be found", meetingID);
|
||||
log.info("Provided ID {} may be an external ID converting to an internal ID", meetingID);
|
||||
|
||||
ParamsProcessorUtil paramsProcessorUtil = new ParamsProcessorUtil();
|
||||
String internalMeetingID = paramsProcessorUtil.convertToInternalMeetingId(meetingID);
|
||||
log.info("Provided ID {} converted to internal ID {}", meetingID, internalMeetingID);
|
||||
|
||||
meeting = meetingService.getMeeting(internalMeetingID);
|
||||
}
|
||||
|
||||
return meeting;
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.bigbluebutton.api.service;
|
||||
|
||||
import org.bigbluebutton.api.MeetingService;
|
||||
import org.bigbluebutton.api.domain.UserSession;
|
||||
|
||||
public class SessionService {
|
||||
|
||||
private String sessionToken;
|
||||
private UserSession userSession;
|
||||
private MeetingService meetingService;
|
||||
|
||||
public SessionService() {
|
||||
meetingService = ServiceUtils.getMeetingService();
|
||||
}
|
||||
|
||||
public void setSessionToken(String sessionToken) {
|
||||
this.sessionToken = sessionToken;
|
||||
getUserSessionWithToken();
|
||||
}
|
||||
|
||||
public String getSessionToken() { return sessionToken; }
|
||||
|
||||
private void getUserSessionWithToken() {
|
||||
if(sessionToken != null) {
|
||||
userSession = meetingService.getUserSessionWithAuthToken(sessionToken);
|
||||
}
|
||||
}
|
||||
|
||||
public String getMeetingID() {
|
||||
if(userSession != null) {
|
||||
return userSession.meetingID;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
package org.bigbluebutton.api.service;
|
||||
|
||||
import org.bigbluebutton.api.model.request.*;
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
import org.bigbluebutton.api.model.shared.GetChecksum;
|
||||
import org.bigbluebutton.api.model.shared.PostChecksum;
|
||||
import org.bigbluebutton.api.util.ParamsUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import java.util.*;
|
||||
|
||||
public class ValidationService {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(ValidationService.class);
|
||||
|
||||
public enum RequestType {
|
||||
GET,
|
||||
POST
|
||||
}
|
||||
|
||||
public enum ApiCall {
|
||||
CREATE("create", RequestType.GET),
|
||||
JOIN("join", RequestType.GET),
|
||||
MEETING_RUNNING("isMeetingRunning", RequestType.GET),
|
||||
END("end", RequestType.GET),
|
||||
GET_MEETING_INFO("getMeetingInfo", RequestType.GET),
|
||||
GET_MEETINGS("getMeetings", RequestType.GET),
|
||||
GET_SESSIONS("getSessions", RequestType.GET),
|
||||
SET_POLL_XML("setPollXML", RequestType.POST),
|
||||
GUEST_WAIT("guestWait", RequestType.GET),
|
||||
ENTER("enter", RequestType.GET),
|
||||
STUNS("stuns", RequestType.GET),
|
||||
SIGN_OUT("signOut", RequestType.GET);
|
||||
|
||||
private final String name;
|
||||
private final RequestType requestType;
|
||||
|
||||
ApiCall(String name, RequestType requestType) {
|
||||
this.name = name;
|
||||
this.requestType = requestType;
|
||||
}
|
||||
|
||||
public String getName() { return this.name; }
|
||||
public RequestType getRequestType() { return this.requestType; }
|
||||
}
|
||||
|
||||
private String securitySalt;
|
||||
private Boolean allowRequestsWithoutSession;
|
||||
|
||||
private ValidatorFactory validatorFactory;
|
||||
private Validator validator;
|
||||
|
||||
public ValidationService() {
|
||||
validatorFactory = Validation.buildDefaultValidatorFactory();
|
||||
validator = validatorFactory.getValidator();
|
||||
}
|
||||
|
||||
public Set<String> validate(ApiCall apiCall, Map<String, String[]> params, String queryString) {
|
||||
log.info("Validating {} request with query string {}", apiCall.getName(), queryString);
|
||||
// log.info("Request has params: {}", mapToString(params));
|
||||
|
||||
params = sanitizeParams(params);
|
||||
|
||||
Request request = initializeRequest(apiCall, params, queryString);
|
||||
Set<String> violations = new HashSet<>();
|
||||
|
||||
if(request == null) {
|
||||
violations.add("validationError: Request not recognized");
|
||||
} else {
|
||||
request.populateFromParamsMap(params);
|
||||
violations = performValidation(request);
|
||||
}
|
||||
|
||||
return violations;
|
||||
}
|
||||
|
||||
private Request initializeRequest(ApiCall apiCall, Map<String, String[]> params, String queryString) {
|
||||
Request request = null;
|
||||
Checksum checksum;
|
||||
|
||||
String checksumValue = "";
|
||||
if(params.containsKey("checksum")) {
|
||||
checksumValue = params.get("checksum")[0];
|
||||
}
|
||||
|
||||
switch(apiCall.requestType) {
|
||||
case GET:
|
||||
checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString);
|
||||
switch(apiCall) {
|
||||
case CREATE:
|
||||
request = new CreateMeeting(checksum);
|
||||
break;
|
||||
case JOIN:
|
||||
request = new JoinMeeting(checksum);
|
||||
break;
|
||||
case MEETING_RUNNING:
|
||||
request = new MeetingRunning(checksum);
|
||||
break;
|
||||
case END:
|
||||
request = new EndMeeting(checksum);
|
||||
break;
|
||||
case GET_MEETING_INFO:
|
||||
request = new MeetingInfo(checksum);
|
||||
break;
|
||||
case SET_POLL_XML:
|
||||
request = new SetPollXML(checksum);
|
||||
break;
|
||||
case GET_MEETINGS:
|
||||
case GET_SESSIONS:
|
||||
request = new SimpleRequest(checksum);
|
||||
break;
|
||||
case GUEST_WAIT:
|
||||
request = new GuestWait();
|
||||
break;
|
||||
case ENTER:
|
||||
request = new Enter();
|
||||
break;
|
||||
case STUNS:
|
||||
request = new Stuns();
|
||||
break;
|
||||
case SIGN_OUT:
|
||||
request = new SignOut();
|
||||
break;
|
||||
}
|
||||
case POST:
|
||||
checksum = new PostChecksum(apiCall.getName(), checksumValue, params);
|
||||
switch(apiCall) {
|
||||
case SET_POLL_XML:
|
||||
request = new SetPollXML(checksum);
|
||||
}
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private <R extends Request> Set<String> performValidation(R classToValidate) {
|
||||
Set<ConstraintViolation<R>> violations = validator.validate(classToValidate);
|
||||
Set<String> violationSet = new HashSet<>();
|
||||
|
||||
for(ConstraintViolation<R> violation: violations) {
|
||||
violationSet.add(violation.getMessage());
|
||||
}
|
||||
|
||||
return violationSet;
|
||||
}
|
||||
|
||||
private Map<String, String[]> sanitizeParams(Map<String, String[]> params) {
|
||||
Map<String, String[]> sanitizedParams = new LinkedHashMap<>();
|
||||
|
||||
for(Map.Entry<String, String[]> param: params.entrySet()) {
|
||||
String paramName = ParamsUtil.sanitizeString(param.getKey());
|
||||
String[] sanitizedValues = new String[param.getValue().length];
|
||||
|
||||
for(int i = 0; i < sanitizedValues.length; i++) {
|
||||
String sanitizedValue = ParamsUtil.sanitizeString(param.getValue()[i]);
|
||||
sanitizedValues[i] = sanitizedValue;
|
||||
}
|
||||
|
||||
sanitizedParams.put(paramName, sanitizedValues);
|
||||
}
|
||||
|
||||
return sanitizedParams;
|
||||
}
|
||||
|
||||
private String mapToString(Map<String, String[]> map) {
|
||||
StringBuilder mapString = new StringBuilder();
|
||||
|
||||
for(Map.Entry<String, String[]> entry: map.entrySet()) {
|
||||
StringBuilder entryString = new StringBuilder();
|
||||
entryString.append(entry.getKey() + ": [");
|
||||
|
||||
for(int i = 0; i < entry.getValue().length; i++) {
|
||||
if(i == entry.getValue().length - 1) {
|
||||
entryString.append(entry.getValue()[i]);
|
||||
} else {
|
||||
entryString.append(entry.getValue()[i] + ", ");
|
||||
}
|
||||
}
|
||||
|
||||
entryString.append("], ");
|
||||
mapString.append(entryString);
|
||||
}
|
||||
|
||||
return mapString.toString();
|
||||
}
|
||||
|
||||
public void setSecuritySalt(String securitySalt) { this.securitySalt = securitySalt; }
|
||||
public String getSecuritySalt() { return securitySalt; }
|
||||
|
||||
public void setAllowRequestsWithoutSession(Boolean allowRequestsWithoutSession) {
|
||||
this.allowRequestsWithoutSession = allowRequestsWithoutSession;
|
||||
}
|
||||
public Boolean getAllowRequestsWithoutSession() { return allowRequestsWithoutSession; }
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
package org.bigbluebutton.api.service;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.bigbluebutton.api.model.request.CreateMeeting;
|
||||
import org.bigbluebutton.api.model.request.JoinMeeting;
|
||||
import org.bigbluebutton.api.model.request.Request;
|
||||
import org.bigbluebutton.api.model.shared.Checksum;
|
||||
import org.bigbluebutton.api.util.ParamsUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class ValidatorService {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(ValidatorService.class);
|
||||
|
||||
public static enum ApiCall {
|
||||
CREATE("create"),
|
||||
JOIN("join");
|
||||
|
||||
private final String name;
|
||||
|
||||
private ApiCall(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() { return this.name; }
|
||||
}
|
||||
|
||||
private static String securitySalt;
|
||||
|
||||
private ValidatorFactory validatorFactory;
|
||||
private Validator validator;
|
||||
|
||||
public ValidatorService() {
|
||||
validatorFactory = Validation.buildDefaultValidatorFactory();
|
||||
validator = validatorFactory.getValidator();
|
||||
}
|
||||
|
||||
public Set<String> validate(ApiCall apiCall, Map<String, String[]> params, String queryString) {
|
||||
log.info("Validating {} request with parameters {}", apiCall.getName(), queryString);
|
||||
|
||||
params = sanitizeParams(params);
|
||||
|
||||
Checksum checksum = new Checksum(apiCall.getName(), params.get("checksum")[0], queryString);
|
||||
|
||||
Request request = null;
|
||||
Set<String> violations = new HashSet<>();
|
||||
|
||||
switch(apiCall) {
|
||||
case CREATE:
|
||||
request = new CreateMeeting(checksum);
|
||||
break;
|
||||
case JOIN:
|
||||
request = new JoinMeeting(checksum);
|
||||
break;
|
||||
default:
|
||||
violations.add("validationError: Request not recognized");
|
||||
break;
|
||||
}
|
||||
|
||||
if(request != null) {
|
||||
request.populateFromParamsMap(params);
|
||||
violations = performValidation(request);
|
||||
}
|
||||
|
||||
return violations;
|
||||
}
|
||||
|
||||
private <R extends Request> Set<String> performValidation(R classToValidate) {
|
||||
Set<ConstraintViolation<R>> violations = validator.validate(classToValidate);
|
||||
Set<String> violationSet = new HashSet<>();
|
||||
|
||||
for(ConstraintViolation<R> violation: violations) {
|
||||
violationSet.add(violation.getMessage());
|
||||
}
|
||||
|
||||
return violationSet;
|
||||
}
|
||||
|
||||
private Map<String, String[]> sanitizeParams(Map<String, String[]> params) {
|
||||
Map<String, String[]> sanitizedParams = new LinkedHashMap<>();
|
||||
|
||||
for(Map.Entry<String, String[]> param: params.entrySet()) {
|
||||
String paramName = ParamsUtil.sanitizeString(param.getKey());
|
||||
String[] sanitizedValues = new String[param.getValue().length];
|
||||
|
||||
for(int i = 0; i < sanitizedValues.length; i++) {
|
||||
String sanitziedValue = ParamsUtil.sanitizeString(param.getValue()[i]);
|
||||
sanitizedValues[i] = sanitziedValue;
|
||||
}
|
||||
|
||||
sanitizedParams.put(paramName, sanitizedValues);
|
||||
}
|
||||
|
||||
return sanitizedParams;
|
||||
}
|
||||
|
||||
public void setSecuritySalt(String securitySalt) { this.securitySalt = securitySalt; }
|
||||
public static String getSecuritySalt() { return securitySalt; }
|
||||
}
|
@ -26,6 +26,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
http://www.springframework.org/schema/util
|
||||
http://www.springframework.org/schema/util/spring-util-2.0.xsd">
|
||||
|
||||
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
|
||||
|
||||
<bean id="characterEncodingFilter" class="org.springframework.web.filter.CharacterEncodingFilter">
|
||||
<property name="encoding">
|
||||
@ -115,8 +116,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<property name="clientConfigServiceHelper" ref="configServiceHelper"/>
|
||||
</bean>
|
||||
|
||||
<bean id="validatorService" class="org.bigbluebutton.api.service.ValidatorService">
|
||||
<bean id="validationService" class="org.bigbluebutton.api.service.ValidationService">
|
||||
<property name="securitySalt" value="${securitySalt}"/>
|
||||
<property name="allowRequestsWithoutSession" value="${allowRequestsWithoutSession}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="serviceUtils" class="org.bigbluebutton.api.service.ServiceUtils">
|
||||
<property name="meetingService" ref="meetingService" />
|
||||
<property name="validationService" ref="validationService" />
|
||||
</bean>
|
||||
|
||||
<bean id="paramsProcessorUtil" class="org.bigbluebutton.api.ParamsProcessorUtil">
|
||||
|
@ -30,7 +30,7 @@ import org.bigbluebutton.api.domain.Config
|
||||
import org.bigbluebutton.api.domain.GuestPolicy
|
||||
import org.bigbluebutton.api.domain.Meeting
|
||||
import org.bigbluebutton.api.domain.UserSession
|
||||
import org.bigbluebutton.api.service.ValidatorService
|
||||
import org.bigbluebutton.api.service.ValidationService
|
||||
import org.bigbluebutton.api.util.ParamsUtil
|
||||
import org.bigbluebutton.api.util.ResponseBuilder
|
||||
import org.bigbluebutton.presentation.PresentationUrlDownloadService
|
||||
@ -61,7 +61,7 @@ class ApiController {
|
||||
StunTurnService stunTurnService
|
||||
HTML5LoadBalancingService html5LoadBalancingService
|
||||
ResponseBuilder responseBuilder = initResponseBuilder()
|
||||
ValidatorService validatorService
|
||||
ValidationService validationService
|
||||
|
||||
def initResponseBuilder = {
|
||||
String protocol = this.getClass().getResource("").getProtocol();
|
||||
@ -97,67 +97,17 @@ class ApiController {
|
||||
log.debug request.getParameterMap().toMapString()
|
||||
log.debug request.getQueryString()
|
||||
|
||||
Set<String> violations = validatorService.validate(
|
||||
ValidatorService.ApiCall.CREATE,
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.CREATE,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
if(!violations.isEmpty()) {
|
||||
StringBuilder violationMessages = new StringBuilder()
|
||||
|
||||
for(String violation: violations) {
|
||||
violationMessages.append(violation + "\n");
|
||||
log.error violation
|
||||
}
|
||||
|
||||
invalid("validationError", violationMessages.toString())
|
||||
if(!validationResponse.isEmpty()) {
|
||||
invalid("validationError", validationResponse)
|
||||
return
|
||||
}
|
||||
|
||||
//sanitizeInput
|
||||
// params.each {
|
||||
// key, value -> params[key] = sanitizeInput(value)
|
||||
// }
|
||||
//
|
||||
// // BEGIN - backward compatibility
|
||||
// if (StringUtils.isEmpty(params.checksum)) {
|
||||
// invalid("checksumError", "You did not pass the checksum security check")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
// params.meetingID = StringUtils.strip(params.meetingID);
|
||||
// if (StringUtils.isEmpty(params.meetingID)) {
|
||||
// invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
// return
|
||||
// }
|
||||
// } else {
|
||||
// invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
// invalid("checksumError", "You did not pass the checksum security check")
|
||||
// return
|
||||
// }
|
||||
// // END - backward compatibility
|
||||
//
|
||||
// ApiErrors errors = new ApiErrors();
|
||||
// paramsProcessorUtil.processRequiredCreateParams(params, errors);
|
||||
//
|
||||
// if (errors.hasErrors()) {
|
||||
// respondWithErrors(errors)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Do we agree with the checksum? If not, complain.
|
||||
// if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
// errors.checksumError()
|
||||
// respondWithErrors(errors)
|
||||
// return
|
||||
// }
|
||||
|
||||
// Ensure unique TelVoice. Uniqueness is not guaranteed by paramsProcessorUtil.
|
||||
if (!params.voiceBridge) {
|
||||
// Try up to 10 times. We should find a valid telVoice quickly unless
|
||||
@ -227,77 +177,17 @@ class ApiController {
|
||||
log.debug request.getParameterMap().toMapString()
|
||||
log.debug request.getQueryString()
|
||||
|
||||
Set<String> violations = validatorService.validate(
|
||||
ValidatorService.ApiCall.JOIN,
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.JOIN,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
if(!violations.isEmpty()) {
|
||||
StringBuilder violationMessages = new StringBuilder()
|
||||
|
||||
for(String violation: violations) {
|
||||
violationMessages.append(violation + "\n");
|
||||
log.error violation
|
||||
}
|
||||
|
||||
invalid("validationError", violationMessages.toString())
|
||||
if(!validationResponse.isEmpty()) {
|
||||
invalid("validationError", validationResponse, REDIRECT_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
// ApiErrors errors = new ApiErrors()
|
||||
//
|
||||
// //sanitizeInput
|
||||
// params.each {
|
||||
// key, value -> params[key] = sanitizeInput(value)
|
||||
// }
|
||||
//
|
||||
// // BEGIN - backward compatibility
|
||||
// if (StringUtils.isEmpty(params.checksum)) {
|
||||
// invalid("checksumError", "You did not pass the checksum security check")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
// invalid("checksumError", "You did not pass the checksum security check")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// //checking for an empty username or for a username containing whitespaces only
|
||||
// if (!StringUtils.isEmpty(params.fullName)) {
|
||||
// params.fullName = StringUtils.strip(params.fullName);
|
||||
// if (StringUtils.isEmpty(params.fullName)) {
|
||||
// invalid("missingParamFullName", "You must specify a name for the attendee who will be joining the meeting.", REDIRECT_RESPONSE);
|
||||
// return
|
||||
// }
|
||||
// } else {
|
||||
// invalid("missingParamFullName", "You must specify a name for the attendee who will be joining the meeting.", REDIRECT_RESPONSE);
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
// params.meetingID = StringUtils.strip(params.meetingID);
|
||||
// if (StringUtils.isEmpty(params.meetingID)) {
|
||||
// invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.", REDIRECT_RESPONSE)
|
||||
// return
|
||||
// }
|
||||
// } else {
|
||||
// invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.", REDIRECT_RESPONSE)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if (StringUtils.isEmpty(params.password)) {
|
||||
// invalid("invalidPassword", "You either did not supply a password or the password supplied is neither the attendee or moderator password for this conference.", REDIRECT_RESPONSE);
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // END - backward compatibility
|
||||
//
|
||||
// // Do we have a checksum? If none, complain.
|
||||
// if (StringUtils.isEmpty(params.checksum)) {
|
||||
// errors.missingParamError("checksum");
|
||||
// }
|
||||
|
||||
Boolean authenticated = false;
|
||||
|
||||
Boolean guest = false;
|
||||
@ -314,60 +204,11 @@ class ApiController {
|
||||
authenticated = Boolean.parseBoolean(params.auth)
|
||||
}
|
||||
|
||||
// Do we have a name for the user joining? If none, complain.
|
||||
if (!StringUtils.isEmpty(params.fullName)) {
|
||||
if (StringUtils.isEmpty(params.fullName)) {
|
||||
errors.missingParamError("fullName");
|
||||
}
|
||||
} else {
|
||||
errors.missingParamError("fullName");
|
||||
}
|
||||
|
||||
String fullName = ParamsUtil.stripControlChars(params.fullName)
|
||||
|
||||
// Do we have a meeting id? If none, complain.
|
||||
// if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
// params.meetingID = StringUtils.strip(params.meetingID);
|
||||
// if (StringUtils.isEmpty(params.meetingID)) {
|
||||
// errors.missingParamError("meetingID");
|
||||
// }
|
||||
// } else {
|
||||
// errors.missingParamError("meetingID");
|
||||
// }
|
||||
// if (!StringUtils.isEmpty(params.fullName)) {
|
||||
// if (StringUtils.isEmpty(params.fullName)) {
|
||||
// errors.missingParamError("fullName");
|
||||
// }
|
||||
// } else {
|
||||
// errors.missingParamError("fullName");
|
||||
// }
|
||||
//
|
||||
// // Do we have a meeting id? If none, complain.
|
||||
// if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
// params.meetingID = StringUtils.strip(params.meetingID);
|
||||
// if (StringUtils.isEmpty(params.meetingID)) {
|
||||
// errors.missingParamError("meetingID");
|
||||
// }
|
||||
// } else {
|
||||
// errors.missingParamError("meetingID");
|
||||
// }
|
||||
String externalMeetingId = params.meetingID
|
||||
|
||||
// Do we have a password? If not, complain.
|
||||
String attPW = params.password
|
||||
// if (StringUtils.isEmpty(attPW)) {
|
||||
// errors.missingParamError("password");
|
||||
// }
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
// if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
// errors.checksumError()
|
||||
// }
|
||||
//
|
||||
// if (errors.hasErrors()) {
|
||||
// respondWithErrors(errors, REDIRECT_RESPONSE)
|
||||
// return
|
||||
// }
|
||||
|
||||
// Everything is good so far. Translate the external meeting id to an internal meeting id. If
|
||||
// we can't find the meeting, complain.
|
||||
@ -375,16 +216,6 @@ class ApiController {
|
||||
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
if (meeting == null) {
|
||||
// BEGIN - backward compatibility
|
||||
invalid("invalidMeetingIdentifier", "The meeting ID that you supplied did not match any existing meetings", REDIRECT_RESPONSE);
|
||||
return
|
||||
// END - backward compatibility
|
||||
|
||||
errors.invalidMeetingIdError();
|
||||
respondWithErrors(errors, REDIRECT_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
// the createTime mismatch with meeting's createTime, complain
|
||||
// In the future, the createTime param will be required
|
||||
@ -408,18 +239,6 @@ class ApiController {
|
||||
}
|
||||
}
|
||||
|
||||
// Is this user joining a meeting that has been ended. If so, complain.
|
||||
if (meeting.isForciblyEnded()) {
|
||||
// BEGIN - backward compatibility
|
||||
invalid("meetingForciblyEnded", "You can not re-join a meeting that has already been forcibly ended. However, once the meeting is removed from memory (according to the timeout configured on this server, you will be able to once again create a meeting with the same meeting ID", REDIRECT_RESPONSE);
|
||||
return
|
||||
// END - backward compatibility
|
||||
|
||||
errors.meetingForciblyEndedError();
|
||||
respondWithErrors(errors, REDIRECT_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
// Now determine if this user is a moderator or a viewer.
|
||||
String role = null;
|
||||
if (meeting.getModeratorPassword().equals(attPW)) {
|
||||
@ -596,66 +415,22 @@ class ApiController {
|
||||
def isMeetingRunning = {
|
||||
String API_CALL = 'isMeetingRunning'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
log.debug request.getParameterMap().toMapString()
|
||||
log.debug request.getQueryString()
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.MEETING_RUNNING,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
if(!validationResponse.isEmpty()) {
|
||||
invalid("validationError", validationResponse)
|
||||
return
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
params.meetingID = StringUtils.strip(params.meetingID);
|
||||
if (StringUtils.isEmpty(params.meetingID)) {
|
||||
invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
return
|
||||
}
|
||||
} else {
|
||||
invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
return
|
||||
}
|
||||
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
return
|
||||
}
|
||||
// END - backward compatibility
|
||||
|
||||
ApiErrors errors = new ApiErrors()
|
||||
|
||||
// Do we have a checksum? If none, complain.
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
errors.missingParamError("checksum");
|
||||
}
|
||||
|
||||
// Do we have a meeting id? If none, complain.
|
||||
if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
params.meetingID = StringUtils.strip(params.meetingID);
|
||||
if (StringUtils.isEmpty(params.meetingID)) {
|
||||
errors.missingParamError("meetingID");
|
||||
}
|
||||
} else {
|
||||
errors.missingParamError("meetingID");
|
||||
}
|
||||
String externalMeetingId = params.meetingID
|
||||
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
}
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
}
|
||||
|
||||
// Everything is good so far. Translate the external meeting id to an internal meeting id. If
|
||||
// we can't find the meeting, complain.
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
@ -680,101 +455,21 @@ class ApiController {
|
||||
String API_CALL = "end"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.END,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
if(!validationResponse.isEmpty()) {
|
||||
invalid("validationError", validationResponse)
|
||||
return
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
params.meetingID = StringUtils.strip(params.meetingID);
|
||||
if (StringUtils.isEmpty(params.meetingID)) {
|
||||
invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
return
|
||||
}
|
||||
} else {
|
||||
invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
return
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(params.password)) {
|
||||
invalid("invalidPassword", "You must supply the moderator password for this call.");
|
||||
return
|
||||
}
|
||||
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
return
|
||||
}
|
||||
// END - backward compatibility
|
||||
|
||||
ApiErrors errors = new ApiErrors()
|
||||
|
||||
// Do we have a checksum? If none, complain.
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
errors.missingParamError("checksum");
|
||||
}
|
||||
|
||||
// Do we have a meeting id? If none, complain.
|
||||
if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
params.meetingID = StringUtils.strip(params.meetingID);
|
||||
if (StringUtils.isEmpty(params.meetingID)) {
|
||||
errors.missingParamError("meetingID");
|
||||
}
|
||||
} else {
|
||||
errors.missingParamError("meetingID");
|
||||
}
|
||||
String externalMeetingId = params.meetingID
|
||||
|
||||
// Do we have a password? If not, complain.
|
||||
String modPW = params.password
|
||||
if (StringUtils.isEmpty(modPW)) {
|
||||
errors.missingParamError("password");
|
||||
}
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
}
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
}
|
||||
|
||||
// Everything is good so far. Translate the external meeting id to an internal meeting id. If
|
||||
// we can't find the meeting, complain.
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId)
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
if (meeting == null) {
|
||||
// BEGIN - backward compatibility
|
||||
invalid("notFound", "We could not find a meeting with that meeting ID - perhaps the meeting is not yet running?");
|
||||
return;
|
||||
// END - backward compatibility
|
||||
|
||||
errors.invalidMeetingIdError();
|
||||
respondWithErrors(errors)
|
||||
return;
|
||||
}
|
||||
|
||||
if (meeting.getModeratorPassword().equals(modPW) == false) {
|
||||
// BEGIN - backward compatibility
|
||||
invalid("invalidPassword", "You must supply the moderator password for this call.");
|
||||
return;
|
||||
// END - backward compatibility
|
||||
|
||||
errors.invalidPasswordError();
|
||||
respondWithErrors(errors)
|
||||
return;
|
||||
}
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId)
|
||||
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingid", meeting.getInternalId());
|
||||
@ -807,79 +502,21 @@ class ApiController {
|
||||
String API_CALL = "getMeetingInfo"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.GET_MEETING_INFO,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
if(!validationResponse.isEmpty()) {
|
||||
invalid("validationError", validationResponse)
|
||||
return
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
params.meetingID = StringUtils.strip(params.meetingID);
|
||||
if (StringUtils.isEmpty(params.meetingID)) {
|
||||
invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
return
|
||||
}
|
||||
} else {
|
||||
invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
return
|
||||
}
|
||||
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
return
|
||||
}
|
||||
// END - backward compatibility
|
||||
|
||||
ApiErrors errors = new ApiErrors()
|
||||
|
||||
// Do we have a checksum? If none, complain.
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
errors.missingParamError("checksum");
|
||||
}
|
||||
|
||||
// Do we have a meeting id? If none, complain.
|
||||
if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
params.meetingID = StringUtils.strip(params.meetingID);
|
||||
if (StringUtils.isEmpty(params.meetingID)) {
|
||||
errors.missingParamError("meetingID");
|
||||
}
|
||||
} else {
|
||||
errors.missingParamError("meetingID");
|
||||
}
|
||||
String externalMeetingId = params.meetingID
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
}
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
}
|
||||
|
||||
// Everything is good so far. Translate the external meeting id to an internal meeting id. If
|
||||
// we can't find the meeting, complain.
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
if (meeting == null) {
|
||||
// BEGIN - backward compatibility
|
||||
invalid("notFound", "We could not find a meeting with that meeting ID");
|
||||
return;
|
||||
// END - backward compatibility
|
||||
|
||||
errors.invalidMeetingIdError();
|
||||
respondWithErrors(errors)
|
||||
return;
|
||||
}
|
||||
|
||||
withFormat {
|
||||
xml {
|
||||
@ -895,39 +532,14 @@ class ApiController {
|
||||
String API_CALL = "getMeetings"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.GET_MEETINGS,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
return
|
||||
}
|
||||
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
return
|
||||
}
|
||||
// END - backward compatibility
|
||||
|
||||
ApiErrors errors = new ApiErrors()
|
||||
|
||||
// Do we have a checksum? If none, complain.
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
errors.missingParamError("checksum");
|
||||
}
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
}
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
if(!validationResponse.isEmpty()) {
|
||||
invalid("validationError", validationResponse)
|
||||
return
|
||||
}
|
||||
|
||||
@ -958,43 +570,18 @@ class ApiController {
|
||||
String API_CALL = "getSessions"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.GET_SESSIONS,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
if(!validationResponse.isEmpty()) {
|
||||
invalid("validationError", validationResponse)
|
||||
return
|
||||
}
|
||||
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
return
|
||||
}
|
||||
// END - backward compatibility
|
||||
|
||||
ApiErrors errors = new ApiErrors()
|
||||
|
||||
// Do we have a checksum? If none, complain.
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
errors.missingParamError("checksum");
|
||||
}
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
}
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
}
|
||||
|
||||
Collection<UserSession> sssns = meetingService.getSessions();
|
||||
Collection<UserSession> sssns = meetingService.getSessions()
|
||||
|
||||
if (sssns == null || sssns.isEmpty()) {
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
@ -1038,43 +625,23 @@ class ApiController {
|
||||
String API_CALL = "setPollXML"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
Map<String, String[]> reqParams = getParameters(request)
|
||||
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.SET_POLL_XML,
|
||||
reqParams,
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
if(!validationResponse.isEmpty()) {
|
||||
invalid("validationError", validationResponse)
|
||||
return
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(params.pollXML)) {
|
||||
invalid("configXMLError", "You did not pass a poll XML")
|
||||
return
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(params.meetingID)) {
|
||||
params.meetingID = StringUtils.strip(params.meetingID);
|
||||
if (StringUtils.isEmpty(params.meetingID)) {
|
||||
invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
return
|
||||
}
|
||||
} else {
|
||||
invalid("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
return
|
||||
}
|
||||
|
||||
// Translate the external meeting id into an internal meeting id.
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(params.meetingID);
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
if (meeting == null) {
|
||||
// BEGIN - backward compatibility
|
||||
invalid("invalidMeetingIdentifier", "The meeting ID that you supplied did not match any existing meetings");
|
||||
return;
|
||||
// END - backward compatibility
|
||||
}
|
||||
|
||||
Map<String, String[]> reqParams = getParameters(request)
|
||||
|
||||
String pollXML = params.pollXML
|
||||
|
||||
@ -1087,37 +654,27 @@ class ApiController {
|
||||
invalid("pollXMLError", "Cannot decode poll XML")
|
||||
return;
|
||||
}
|
||||
def pollxml = new XmlSlurper().parseText(decodedPollXML);
|
||||
|
||||
if (!paramsProcessorUtil.isPostChecksumSame(API_CALL, reqParams)) {
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
withFormat {
|
||||
xml {
|
||||
invalid("pollXMLChecksumError", "pollXMLChecksumError: request did not pass the checksum security check.")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
def pollxml = new XmlSlurper().parseText(decodedPollXML);
|
||||
pollxml.children().each { poll ->
|
||||
String title = poll.title.text();
|
||||
String question = poll.question.text();
|
||||
String questionType = poll.questionType.text();
|
||||
|
||||
pollxml.children().each { poll ->
|
||||
String title = poll.title.text();
|
||||
String question = poll.question.text();
|
||||
String questionType = poll.questionType.text();
|
||||
|
||||
ArrayList<String> answers = new ArrayList<String>();
|
||||
poll.answers.children().each { answer ->
|
||||
answers.add(answer.text());
|
||||
}
|
||||
|
||||
//send poll to BigBlueButton Apps
|
||||
meetingService.createdPolls(meeting.getInternalId(), title, question, questionType, answers);
|
||||
ArrayList<String> answers = new ArrayList<String>();
|
||||
poll.answers.children().each { answer ->
|
||||
answers.add(answer.text());
|
||||
}
|
||||
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
withFormat {
|
||||
xml {
|
||||
// No need to use the response builder here until we have a more complex response
|
||||
render(text: "<response><returncode>$RESP_CODE_SUCCESS</returncode></response>", contentType: "text/xml")
|
||||
}
|
||||
//send poll to BigBlueButton Apps
|
||||
meetingService.createdPolls(meeting.getInternalId(), title, question, questionType, answers);
|
||||
}
|
||||
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
withFormat {
|
||||
xml {
|
||||
// No need to use the response builder here until we have a more complex response
|
||||
render(text: "<response><returncode>$RESP_CODE_SUCCESS</returncode></response>", contentType: "text/xml")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1129,45 +686,20 @@ class ApiController {
|
||||
String API_CALL = 'guestWait'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
ApiErrors errors = new ApiErrors()
|
||||
String msgKey = "defaultKey"
|
||||
String msgValue = "defaultValue"
|
||||
String destURL = paramsProcessorUtil.getDefaultLogoutUrl()
|
||||
|
||||
// Do we have a sessionToken? If none, complain.
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
if (sessionToken == null) {
|
||||
msgKey = "missingToken"
|
||||
msgValue = "Guest missing session token."
|
||||
respondWithJSONError(msgKey, msgValue, destURL)
|
||||
return
|
||||
}
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.GUEST_WAIT,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
UserSession us = getUserSession(sessionToken)
|
||||
if (us == null) {
|
||||
msgKey = "missingSession"
|
||||
msgValue = "Guest missing session."
|
||||
respondWithJSONError(msgKey, msgValue, destURL)
|
||||
return
|
||||
}
|
||||
|
||||
Meeting meeting = meetingService.getMeeting(us.meetingID)
|
||||
if (meeting == null) {
|
||||
msgKey = "missingMeeting"
|
||||
msgValue = "Meeting does not exist."
|
||||
respondWithJSONError(msgKey, msgValue, destURL)
|
||||
return
|
||||
}
|
||||
|
||||
// Is this user joining a meeting that has been ended. If so, complain.
|
||||
if (meeting.isForciblyEnded()) {
|
||||
msgKey = "meetingEnded"
|
||||
msgValue = "Meeting ended."
|
||||
if(!validationResponse.isEmpty()) {
|
||||
msgKey = "validationError"
|
||||
msgValue = validationResponse
|
||||
respondWithJSONError(msgKey, msgValue, destURL)
|
||||
return
|
||||
}
|
||||
@ -1253,47 +785,34 @@ class ApiController {
|
||||
String API_CALL = 'enter'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
String respMessage = "Session not found."
|
||||
boolean reject = false;
|
||||
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
UserSession us = getUserSession(sessionToken);
|
||||
Meeting meeting = null;
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.ENTER,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
String respMessage = "Session not found."
|
||||
if(!validationResponse.isEmpty()) {
|
||||
respMessage = validationResponse
|
||||
reject = true
|
||||
}
|
||||
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
UserSession us = getUserSession(sessionToken)
|
||||
Meeting meeting = meetingService.getMeeting(us.meetingID)
|
||||
meeting.userEntered(us.internalUserId)
|
||||
|
||||
if (!hasValidSession(sessionToken)) {
|
||||
reject = true;
|
||||
} else {
|
||||
meeting = meetingService.getMeeting(us.meetingID);
|
||||
if (meeting == null || meeting.isForciblyEnded()) {
|
||||
reject = true
|
||||
respMessage = "Meeting not found or ended for session."
|
||||
} else {
|
||||
if (hasReachedMaxParticipants(meeting, us)) {
|
||||
reject = true;
|
||||
respMessage = "The number of participants allowed for this meeting has been reached.";
|
||||
} else {
|
||||
meeting.userEntered(us.internalUserId);
|
||||
}
|
||||
}
|
||||
if (us.guestStatus.equals(GuestPolicy.DENY)) {
|
||||
respMessage = "User denied for user with session."
|
||||
reject = true
|
||||
}
|
||||
}
|
||||
|
||||
if (reject) {
|
||||
// Determine the logout url so we can send the user there.
|
||||
String logoutUrl = paramsProcessorUtil.getDefaultLogoutUrl()
|
||||
|
||||
if (us != null) {
|
||||
logoutUrl = us.logoutUrl
|
||||
}
|
||||
logoutUrl = us.logoutUrl
|
||||
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
withFormat {
|
||||
@ -1404,24 +923,24 @@ class ApiController {
|
||||
String API_CALL = 'stuns'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
boolean reject = false;
|
||||
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.STUNS,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
if(!validationResponse.isEmpty()) {
|
||||
reject = true
|
||||
}
|
||||
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
UserSession us = getUserSession(sessionToken);
|
||||
Meeting meeting = null;
|
||||
UserSession us = getUserSession(sessionToken)
|
||||
Meeting meeting = meetingService.getMeeting(us.meetingID)
|
||||
|
||||
if (!hasValidSession(sessionToken)) {
|
||||
reject = true;
|
||||
} else {
|
||||
meeting = meetingService.getMeeting(us.meetingID);
|
||||
if (meeting == null || meeting.isForciblyEnded()) {
|
||||
reject = true
|
||||
}
|
||||
}
|
||||
|
||||
if (reject) {
|
||||
@ -1483,38 +1002,32 @@ class ApiController {
|
||||
String API_CALL = 'signOut'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
String validationResponse = validateRequest(
|
||||
ValidationService.ApiCall.SIGN_OUT,
|
||||
request.getParameterMap(),
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
|
||||
Meeting meeting = null;
|
||||
|
||||
if (sessionToken != null) {
|
||||
|
||||
UserSession us = meetingService.removeUserSessionWithAuthToken(sessionToken);
|
||||
if (us != null) {
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingid", us.meetingID);
|
||||
logData.put("extMeetingid", us.externMeetingID);
|
||||
logData.put("name", us.fullname);
|
||||
logData.put("userid", us.internalUserId);
|
||||
logData.put("sessionToken", sessionToken);
|
||||
logData.put("message", "handle_signout_api");
|
||||
logData.put("logCode", "signout_api");
|
||||
logData.put("description", "Handling SIGNOUT API.");
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
log.info(" --analytics-- data=" + logStr);
|
||||
} else {
|
||||
log.info("Could not find user session for session token {}", sessionToken)
|
||||
}
|
||||
if(validationResponse.isEmpty()) {
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
UserSession us = meetingService.removeUserSessionWithAuthToken(sessionToken)
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingid", us.meetingID);
|
||||
logData.put("extMeetingid", us.externMeetingID);
|
||||
logData.put("name", us.fullname);
|
||||
logData.put("userid", us.internalUserId);
|
||||
logData.put("sessionToken", sessionToken);
|
||||
logData.put("message", "handle_signout_api");
|
||||
logData.put("logCode", "signout_api");
|
||||
logData.put("description", "Handling SIGNOUT API.");
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
log.info(" --analytics-- data=" + logStr)
|
||||
|
||||
session.removeAttribute(sessionToken)
|
||||
} else {
|
||||
log.info("Could not find user session for session token {}", params.sessionToken)
|
||||
}
|
||||
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
@ -1726,7 +1239,7 @@ class ApiController {
|
||||
return us
|
||||
}
|
||||
|
||||
// Can be removed. Input sanitization is performed in the ValidatorService.
|
||||
// Can be removed. Input sanitization is performed in the ValidationService.
|
||||
private def sanitizeInput (input) {
|
||||
if(input == null)
|
||||
return
|
||||
@ -1907,4 +1420,18 @@ class ApiController {
|
||||
redirect(url: newUri)
|
||||
}
|
||||
|
||||
private String validateRequest(ValidationService.ApiCall apiCall, Map<String, String[]> params, String queryString) {
|
||||
Set<String> violations = validationService.validate(apiCall, params, queryString)
|
||||
StringBuilder violationMessages = new StringBuilder()
|
||||
|
||||
if(!violations.isEmpty()) {
|
||||
for(String violation: violations) {
|
||||
violationMessages.append(violation + "\n");
|
||||
log.error violation
|
||||
}
|
||||
}
|
||||
|
||||
return violationMessages.toString()
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user